11 Commits
v1.3 ... v1.4.2

22 changed files with 409 additions and 116 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
.cache/
build/
.vscode/
result

View File

@@ -1,17 +1,69 @@
cmake_minimum_required(VERSION 3.10.0)
project(hyprland-toggle-tiling VERSION 0.1.0 LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.16)
project(hyprland-toggle-tiling
VERSION 1.4.2
LANGUAGES CXX
)
include(GNUInstallDirs)
include(FetchContent)
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz)
FetchContent_MakeAvailable(json)
# --------------------------------------------------
# Dependency handling
# --------------------------------------------------
option(USE_SYSTEM_JSON
"Use system-installed nlohmann_json instead of fetching"
OFF
)
if(USE_SYSTEM_JSON)
find_package(nlohmann_json CONFIG REQUIRED)
else()
# Try system package first silently
find_package(nlohmann_json CONFIG QUIET)
if(NOT nlohmann_json_FOUND)
message(STATUS "nlohmann_json not found, fetching from GitHub")
FetchContent_Declare(
nlohmann_json
URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
)
FetchContent_MakeAvailable(nlohmann_json)
else()
message(STATUS "Using system nlohmann_json")
endif()
endif()
# --------------------------------------------------
# Executable
# --------------------------------------------------
add_executable(htt
src/main.cpp
src/HyprlandService.cpp
src/Workspace.cpp
src/ShellService.cpp
src/FileService.cpp
src/WindowRule.cpp
src/Client.cpp)
target_link_libraries(htt PRIVATE nlohmann_json::nlohmann_json)
target_include_directories(htt PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
src/main.cpp
src/HyprlandService.cpp
src/Workspace.cpp
src/ShellService.cpp
src/FileService.cpp
src/WindowRule.cpp
src/Client.cpp
)
target_compile_features(htt PRIVATE cxx_std_17)
target_link_libraries(htt
PRIVATE
nlohmann_json::nlohmann_json
)
target_include_directories(htt PRIVATE ${PROJECT_SOURCE_DIR}/src)
# --------------------------------------------------
# Install
# --------------------------------------------------
install(TARGETS htt
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

View File

@@ -29,6 +29,8 @@ Check out [the demo](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-til
Let's say you switched to tiling mode. From that point on, new windows will open in tiling mode as well.
Switch to floating mode again and newly opened windows will be in floating mode.
- Floating/tiling window rules are isolated between workspaces. You can set one workspace to be floating, and all the rest to tiling for example.
- Returns applied rule for the current workspace. Useful for scripting.
- Moving a window from a tiling workspace to a floating one changes the float state of the window to respect the new workspace.
- Useful for workflows that require both tiling and floating window management.
- Lightweight and easy to integrate with your Hyprland setup.
@@ -40,6 +42,34 @@ You have a few options of obtainting the program.
You may install this program [from the AUR.](https://aur.archlinux.org/packages/hyprland-toggle-tiling-git)
### Nix Flake (for Nix users)
This project provides a Nix flake for reproducible builds and easy installation.
#### Build the package
```shell
nix build git+ssh://gitea@typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling.git
```
The binary will be at `./result/bin/htt`.
#### Add to Home Manager
1. Add the flake as an input:
```shell
inputs.htt.url = "git+ssh://gitea@typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling.git";
```
2. Then include it in your configuration:
```shell
home.packages = [
inputs.htt.packages.${pkgs.system}.default
];
```
### Download the release
You can also [download the release binary.](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases)
@@ -75,8 +105,21 @@ or go nuts and...
# Usage
```shell
./htt <config-file-path>
./htt <config-file-path> (flags)
```
- `-q`: Print the rule applied on the current workspace to STDOUT, but don't change anything. If there isn't an active rule for the current workspace, it returns a tiling rule. The returned string is a valid Hyprland window rule configuration line, like so:
```shell
# (On workspace 2...)
$ ./htt ~/.cache/htt/rules -q
windowrule = tile on, match:workspace 2
```
Potential applications for this are mainly scripts, like my waybar module here:
![wayland module showcase](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/raw/branch/master/assets/waybar_module.gif)
- `-m [integer]`: Move currently active window to specified workspace. Upon moving, the window will adapt to the windowing mode of the new workspace. Doesn't work with `-q`. See ![the 1.4 changelog](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases/tag/v1.4) for details.
- If the specified configuration file does not exist, it will be created.
- If the configuration contains existing rules, this should still work, but your existing configuration will probably get a bit messy, syntax-wise. I advise against it.
@@ -92,5 +135,37 @@ or go nuts and...
bind = $mod + t, exec, /path/to/htt <config-file-path>
```
Or not. Do whatever you want.
3. If you want windows to respect workspaces' rules after moving them to another workspace (see ![the 1.4 changelog](https://typofelho.ddns.net/TypoMustakes/hyprland-toggle-tiling/releases/tag/v1.4) for details), you might want to tell HTT to move your windows instead of telling Hyprland.
On the default configuration, this would mean changing this:
```sh
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2
bind = $mainMod SHIFT, 3, movetoworkspace, 3
bind = $mainMod SHIFT, 4, movetoworkspace, 4
bind = $mainMod SHIFT, 5, movetoworkspace, 5
bind = $mainMod SHIFT, 6, movetoworkspace, 6
bind = $mainMod SHIFT, 7, movetoworkspace, 7
bind = $mainMod SHIFT, 8, movetoworkspace, 8
bind = $mainMod SHIFT, 9, movetoworkspace, 9
bind = $mainMod SHIFT, 0, movetoworkspace, 10
```
to this:
```sh
bind = $mainMod SHIFT, 1, exec, htt [your htt config file] -m 1
bind = $mainMod SHIFT, 2, exec, htt [your htt config file] -m 2
bind = $mainMod SHIFT, 3, exec, htt [your htt config file] -m 3
bind = $mainMod SHIFT, 4, exec, htt [your htt config file] -m 4
bind = $mainMod SHIFT, 5, exec, htt [your htt config file] -m 5
bind = $mainMod SHIFT, 6, exec, htt [your htt config file] -m 6
bind = $mainMod SHIFT, 7, exec, htt [your htt config file] -m 7
bind = $mainMod SHIFT, 8, exec, htt [your htt config file] -m 8
bind = $mainMod SHIFT, 9, exec, htt [your htt config file] -m 9
bind = $mainMod SHIFT, 0, exec, htt [your htt config file] -m 10
```
... in your configuration.
Otherwise, just use `exec, htt [your htt config file] -m [workspace ID]` wherever you used `movetoworkspace [workspace ID]` before.

BIN
assets/waybar_module.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

37
default.nix Normal file
View File

@@ -0,0 +1,37 @@
{ pkgs ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation rec {
pname = "hyprland-toggle-tiling";
version = "1.4.2";
src = pkgs.fetchFromGitHub {
owner = "TypoMustakes";
repo = "hyprland-toggle-tiling";
rev = "v${version}";
sha256 = "sha256-NxNT2pZ4zWkF5JPPUcqJl+VFOIHyxq4ZsACg9GsWnwM=";
};
nativeBuildInputs = [
pkgs.cmake
pkgs.pkg-config
];
buildInputs = [
pkgs.hyprland
pkgs.nlohmann_json
];
cmakeFlags = [
"-DUSE_SYSTEM_JSON=ON"
];
cmakeBuildType = "Release";
meta = with pkgs.lib; {
description = "Toggle tiling and floating modes in Hyprland globally.";
homepage = "https://github.com/TypoMustakes/hyprland-toggle-tiling";
license = licenses.gpl3Only;
platforms = platforms.linux;
mainProgram = "htt";
};
}

27
flake.lock generated Normal file
View File

@@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1775710090,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

20
flake.nix Normal file
View File

@@ -0,0 +1,20 @@
{
description = "hyprland-toggle-tiling";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in
{
packages.${system}.default = pkgs.callPackage ./default.nix {};
apps.${system}.default = {
type = "app";
program = "${self.packages.${system}.default}/bin/htt";
};
};
}

View File

@@ -23,7 +23,6 @@ class Client {
std::array<int, 2> size;
WorkspaceSignature workspace;
bool floating;
bool pseudo;
int monitor;
std::string className;
std::string title;
@@ -34,6 +33,7 @@ class Client {
bool pinned;
int fullscreen;
int fullscreenClient;
bool overFullscreen;
std::string swallowing;
int focusHistory;
bool inhibitingIdle;

View File

@@ -2,26 +2,36 @@
#define HYPRLAND_SERVICE_H
#include <list>
#include "Workspace.h"
#include "Client.h"
#include "WindowRule.h"
#include "Workspace.hpp"
#include "Client.hpp"
#include "WindowRule.hpp"
class HyprlandService {
private:
static std::string configFilePath;
public:
static void setConfigFilePath(std::string);
static std::string getConfigFilePath();
static std::list<Workspace> getWorkspaces();
static std::optional<Workspace> getWorkspace(int);
static Workspace getCurrentWorkspace();
static std::list<Client> getClients();
static std::list<Client> getClientsOnActiveWorkspace();
static Client getActiveClient();
static bool isFloatingRulePresent(int);
static bool isFloatingRulePresent(Workspace);
static std::list<WindowRule> getWindowRules();
static std::optional<WindowRule> findConflictingRule(WindowRule);
static void setFloatingRule(bool);
static void removeRule(WindowRule);
static void setClientFloating(Client&);
static void setClientTiled(Client&);
static void toggleClientFloating(Client&);
static bool isFloatingRulePresent();
static void setClientFloating(Client);
static void setClientTiled(Client);
public:
static void toggleFloating();
static void moveToWorkspace(int);
static void setConfigFilePath(std::string);
static WindowRule getActiveWorkspaceRule();
};
#endif

View File

@@ -1,9 +0,0 @@
#ifndef MACROS_H
#define MACROS_H
#define HYPRCTL_BINARY "/usr/bin/hyprctl"
#define NULL_PATH "/dev/null"
#define ECHO_PATH "/usr/bin/echo"
#define CAT_PATH "/usr/bin/cat"
#endif

9
include/Macros.hpp Normal file
View File

@@ -0,0 +1,9 @@
#ifndef MACROS_H
#define MACROS_H
#define HYPRCTL_BINARY "hyprctl"
#define NULL_PATH "/dev/null"
#define ECHO_PATH "echo"
#define CAT_PATH "cat"
#endif

View File

@@ -1,4 +1,4 @@
#include "../include/Client.h"
#include "../include/Client.hpp"
void from_json(const json& j, WorkspaceSignature& ws) {
j.at("id").get_to(ws.id);
@@ -12,7 +12,6 @@ void from_json(const json& j, Client& client) {
j.at("size").get_to(client.size);
j.at("workspace").get_to(client.workspace);
j.at("floating").get_to(client.floating);
j.at("pseudo").get_to(client.pseudo);
j.at("monitor").get_to(client.monitor);
j.at("class").get_to(client.className); // Maps "class" JSON field to className
j.at("title").get_to(client.title);
@@ -23,6 +22,7 @@ void from_json(const json& j, Client& client) {
j.at("pinned").get_to(client.pinned);
j.at("fullscreen").get_to(client.fullscreen);
j.at("fullscreenClient").get_to(client.fullscreenClient);
j.at("overFullscreen").get_to(client.overFullscreen);
j.at("swallowing").get_to(client.swallowing);
j.at("focusHistoryID").get_to(client.focusHistory);
j.at("inhibitingIdle").get_to(client.inhibitingIdle);

View File

@@ -1,8 +1,8 @@
#include <sstream>
#include <fstream>
#include "../include/FileService.h"
#include "../include/Macros.h"
#include "../include/ShellService.h"
#include "../include/FileService.hpp"
#include "../include/Macros.hpp"
#include "../include/ShellService.hpp"
bool FileService::doesNonEmptyFileExist(std::string path) {
std::ifstream file(path);

View File

@@ -1,15 +1,17 @@
#include "../include/HyprlandService.hpp"
#include "../include/FileService.hpp"
#include "../include/Macros.hpp"
#include "../include/ShellService.hpp"
#include <nlohmann/json.hpp>
#include "../include/HyprlandService.h"
#include "../include/ShellService.h"
#include "../include/Macros.h"
#include "../include/FileService.h"
#include <optional>
#include <string>
using json = nlohmann::json;
std::string HyprlandService::configFilePath;
void HyprlandService::setConfigFilePath(std::string path) {
//Look for substring "~/". If found, expand it
// Look for substring "~/". If found, expand it
const std::string tilde = "~/";
size_t pos = path.find(tilde);
if (pos != std::string::npos) {
@@ -18,15 +20,38 @@ void HyprlandService::setConfigFilePath(std::string path) {
configFilePath = path;
};
std::string HyprlandService::getConfigFilePath() {
return configFilePath;
};
std::string HyprlandService::getConfigFilePath() { return configFilePath; };
std::list<Workspace> HyprlandService::getWorkspaces() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " workspaces -j"));
return j.get<std::list<Workspace>>();
}
std::optional<Workspace> HyprlandService::getWorkspace(int id) {
std::list<Workspace> workspaces = getWorkspaces();
for (auto it = workspaces.begin(); it != workspaces.end();) {
if (it->id == id) {
return *it;
} else {
++it;
}
}
return std::nullopt;
}
Workspace HyprlandService::getCurrentWorkspace() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activeworkspace -j"));
json j =
json::parse(ShellService::exec(HYPRCTL_BINARY " activeworkspace -j"));
return j.get<Workspace>();
};
Client HyprlandService::getActiveClient() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " activewindow -j"));
return j.get<Client>();
}
std::list<Client> HyprlandService::getClients() {
json j = json::parse(ShellService::exec(HYPRCTL_BINARY " clients -j"));
return j.get<std::list<Client>>();
@@ -36,7 +61,7 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
std::list<Client> clients = getClients();
int activeWorkspaceID = getCurrentWorkspace().id;
for (auto it = clients.begin(); it != clients.end(); ) {
for (auto it = clients.begin(); it != clients.end();) {
if (it->workspace.id != activeWorkspaceID) {
it = clients.erase(it);
} else {
@@ -50,47 +75,42 @@ std::list<Client> HyprlandService::getClientsOnActiveWorkspace() {
std::list<WindowRule> HyprlandService::getWindowRules() {
std::list<WindowRule> rules;
for (auto& line : FileService::readLines(getConfigFilePath())) {
for (auto &line : FileService::readLines(getConfigFilePath())) {
rules.push_back(WindowRule::parse(line));
}
return rules;
};
void HyprlandService::setClientFloating(Client& c) {
ShellService::exec(HYPRCTL_BINARY " dispatch setfloating address:" + c.address);
void HyprlandService::setClientFloating(Client c) {
ShellService::exec(HYPRCTL_BINARY " dispatch setfloating address:" +
c.address);
};
void HyprlandService::setClientTiled(Client& c) {
void HyprlandService::setClientTiled(Client c) {
ShellService::exec(HYPRCTL_BINARY " dispatch settiled address:" + c.address);
}
void HyprlandService::toggleClientFloating(Client& c) {
ShellService::exec(HYPRCTL_BINARY " dispatch togglefloating address:" + c.address);
};
//on = true -> creates a window rule to ENABLE floating mode for currently active workspace
//on = false -> creates a window rule to DISABLE floating mode for currently active workspace
// on = true -> creates a window rule to ENABLE floating mode for currently
// active workspace on = false -> creates a window rule to DISABLE floating mode
// for currently active workspace
void HyprlandService::setFloatingRule(bool on) {
WindowRule rule {.tile = !on, .workspaceID = getCurrentWorkspace().id};
WindowRule rule{.tile = !on, .workspaceID = getCurrentWorkspace().id};
auto conflictingRule = findConflictingRule(rule);
if (conflictingRule.has_value()) {
removeRule(conflictingRule.value());
}
FileService::appendToFile(
getConfigFilePath(),
rule.toString()
);
FileService::appendToFile(getConfigFilePath(), rule.toString());
};
std::optional<WindowRule> HyprlandService::findConflictingRule(WindowRule subject) {
std::optional<WindowRule>
HyprlandService::findConflictingRule(WindowRule subject) {
std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id;
for (auto& rule : rules) {
if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID)
{
for (auto &rule : rules) {
if (rule.tile == !subject.tile && rule.workspaceID == subject.workspaceID) {
return rule;
}
}
@@ -103,9 +123,8 @@ void HyprlandService::removeRule(WindowRule rule) {
int index = 0;
int foundIndex = -1;
for (auto& it : rules) {
if (it.toString() == rule.toString())
{
for (auto &it : rules) {
if (it.toString() == rule.toString()) {
foundIndex = index;
break;
}
@@ -113,25 +132,63 @@ void HyprlandService::removeRule(WindowRule rule) {
}
if (foundIndex != -1) {
FileService::deleteNthLine(
getConfigFilePath(),
foundIndex
);
FileService::deleteNthLine(getConfigFilePath(), foundIndex);
}
//else: rule not found, do nothing
// else: rule not found, do nothing
}
bool HyprlandService::isFloatingRulePresent() {
//Checks if there's a valid window rule in place that enables floating mode for the currently active workspace
bool HyprlandService::isFloatingRulePresent(int workspaceId) {
std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id;
for (auto& rule : rules) {
if (rule.workspaceID == id && rule.tile == false) {
for (auto &rule : rules) {
if (rule.workspaceID == workspaceId && rule.tile == false) {
return true;
}
}
return false;
}
bool HyprlandService::isFloatingRulePresent(Workspace workspace) {
return isFloatingRulePresent(workspace.id);
};
WindowRule HyprlandService::getActiveWorkspaceRule() {
std::list<WindowRule> rules = getWindowRules();
int id = getCurrentWorkspace().id;
for (auto &rule : rules) {
if (rule.workspaceID == id) {
return rule;
}
}
// If no rule is found, return a default rule (tiled)
return WindowRule{.tile = true, .workspaceID = id};
};
void HyprlandService::moveToWorkspace(int workspaceId) {
if (isFloatingRulePresent(workspaceId)) {
setClientFloating(getActiveClient());
} else {
setClientTiled(getActiveClient());
}
ShellService::exec(HYPRCTL_BINARY " dispatch movetoworkspace " +
std::to_string(workspaceId));
}
void HyprlandService::toggleFloating() {
if (isFloatingRulePresent(getCurrentWorkspace())) {
for (auto &c : getClientsOnActiveWorkspace()) {
setClientTiled(c);
}
setFloatingRule(false);
} else {
for (auto &c : getClientsOnActiveWorkspace()) {
setClientFloating(c);
}
setFloatingRule(true);
}
}

View File

@@ -1,40 +1,41 @@
#include "../include/ShellService.h"
#include "../include/ShellService.hpp"
#include <pwd.h>
#include <unistd.h>
std::string ShellService::exec(const std::string& command) {
std::string ShellService::exec(const std::string &command) {
char buffer[128];
std::string result = "";
FILE* pipe = popen(command.c_str(), "r");
FILE *pipe = popen(command.c_str(), "r");
if (!pipe) {
return "popen failed";
return "popen failed";
}
while (fgets(buffer, sizeof(buffer), pipe) != NULL) {
result += buffer;
result += buffer;
}
int status = pclose(pipe);
if (status == -1) {
return "Error closing pipe";
return "Error closing pipe";
}
return result;
};
std::string ShellService::getHomePath()
{
char* home = getenv("HOME");
std::string ShellService::getHomePath() {
char *home = getenv("HOME");
if (home && *home) {
return std::string(home);
return std::string(home) + std::string("/");
}
// Fallback: try to get home directory from passwd if HOME is not set
// This assumes that the 'htt' process is ran with the user as the process owner. Should it be run with systemd or some other wonky method, it will behave unexpectedly
struct passwd* pw = getpwuid(getuid());
// This assumes that the 'htt' process is ran with the user as the process
// owner. Should it be run with systemd or some other wonky method, it will
// behave unexpectedly
struct passwd *pw = getpwuid(getuid());
if (pw && pw->pw_dir) {
return std::string(pw->pw_dir);
return std::string(pw->pw_dir);
}
// As a last resort, exit

View File

@@ -1,5 +1,5 @@
#include <algorithm>
#include "../include/WindowRule.h"
#include "../include/WindowRule.hpp"
std::string WindowRule::toString() {
std::string mode = this->tile ? "tile on" : "float on";

View File

@@ -1,4 +1,4 @@
#include "../include/Workspace.h"
#include "../include/Workspace.hpp"
void from_json(const nlohmann::json &j, Workspace &w) {
j.at("id").get_to(w.id);

View File

@@ -1,23 +1,36 @@
#include <iostream>
#include "../include/HyprlandService.h"
#include <stdexcept>
#include "../include/HyprlandService.hpp"
int main(int argc, char** argv){
if (argc < 2) {
std::cerr << "Usage: " << argv[0] << " <config_file_path>\n";
void help(char* execPath) {
std::cerr << "Usage: " << execPath << " <config_file_path> (flags)\n\n";
std::cerr << "Flags:\n\n";
std::cerr << "-q:\t\tQuery current windowing mode, don't change anything.\n\t\tReturns Hyprland window rule active on current workspace.\n\t\tIf no rule is active, returns a default tiled rule.\n\n";
std::cerr << "-m [integer]:\tMove currently active window to specified workspace.\n\t\tUpon moving, the window will adapt to the windowing mode of the new workspace.\n\t\tDoesn't work with -q.\n";
exit(1);
}
HyprlandService::setConfigFilePath(argv[1]);
if (HyprlandService::isFloatingRulePresent()) {
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
HyprlandService::setClientTiled(c);
}
HyprlandService::setFloatingRule(false);
} else {
for (auto& c : HyprlandService::getClientsOnActiveWorkspace()) {
HyprlandService::setClientFloating(c);
}
HyprlandService::setFloatingRule(true);
}
}
int main(int argc, char** argv) {
if (argc >= 2) {
HyprlandService::setConfigFilePath(argv[1]);
if (argc == 2) {
HyprlandService::toggleFloating();
}
else if (argc == 3 && argv[2] == std::string("-q")) {
std::cout << HyprlandService::getActiveWorkspaceRule().toString() << std::endl;
} else if (argc == 4 && argv[2] == std::string("-m")) {
try {
HyprlandService::moveToWorkspace(std::stoi(argv[3]));
} catch (std::invalid_argument) {
help(argv[0]);
}
} else {
help(argv[0]);
}
} else {
help(argv[0]);
}
exit(0);
}