Skip to content

Instantly share code, notes, and snippets.

@Rapptz
Last active February 21, 2024 03:50
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Rapptz/9664773178da1bc397cf to your computer and use it in GitHub Desktop.
Save Rapptz/9664773178da1bc397cf to your computer and use it in GitHub Desktop.
Windows port of xclip
// The MIT License (MIT)
// Copyright (c) 2014 Rapptz
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cstdlib>
struct clipboard {
private:
bool open;
public:
clipboard(HWND owner = nullptr): open(OpenClipboard(owner)) {}
clipboard(const clipboard&) = delete;
clipboard(clipboard&&) = delete;
clipboard& operator=(const clipboard&) = delete;
clipboard& operator=(clipboard&&) = delete;
~clipboard() {
if(open) {
CloseClipboard();
}
}
bool clear() const noexcept {
return EmptyClipboard();
}
bool is_open() const noexcept {
return open;
}
bool copy(const std::string& str) const {
if(open) {
clear();
HGLOBAL buffer = GlobalAlloc(GMEM_DDESHARE, str.size() + 1);
if(buffer) {
std::copy(std::begin(str), std::end(str), static_cast<char*>(GlobalLock(buffer)));
GlobalUnlock(buffer);
return SetClipboardData(CF_TEXT, buffer) != nullptr;
}
}
return false;
}
// no error checking on purpose
std::string paste() const {
return static_cast<char*>(GetClipboardData(CF_TEXT));
}
};
int help() {
std::cout <<
"usage: xclip [options]\n\n"
" -i, --in reads text from stdin (default)\n"
" -o, --out outputs text to stdout\n"
" -f, --file <filename> reads text from a file\n"
" -v, --version outputs version information\n"
" -h, --help prints this message and exits\n";
return EXIT_SUCCESS;
}
int version() {
std::cout <<
"xclip version 1.0 (Windows native port)\n"
"Written by Rapptz\n\n"
"Copyright (C) 2014 Rapptz\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
return EXIT_SUCCESS;
}
int error(const char* str) {
std::cout << "xclip: error: " << str << '\n';
return EXIT_FAILURE;
}
int read_text(const clipboard& clip) {
std::ostringstream ss;
for(std::string line; std::getline(std::cin, line); ) {
ss << line;
}
return clip.copy(ss.str()) ? EXIT_SUCCESS : EXIT_FAILURE;
}
int read_file(const clipboard& clip, const std::string& filename) {
if(filename.empty()) {
return error("no input file given");
}
std::ifstream in(filename);
std::ostringstream ss;
ss << in.rdbuf();
return clip.copy(ss.str()) ? EXIT_SUCCESS : EXIT_FAILURE;
}
int main(int argc, char** argv) {
clipboard clip;
if(!clip.is_open()) {
return error("unable to open clipboard");
}
std::vector<std::string> args{argv, argv + argc};
if(argc < 2) {
return read_text(clip);
}
for(int i = 1; i < argc; ++i) {
auto&& arg = args[i];
if(arg == "-h" || arg == "--help") {
return help();
}
if(arg == "-v" || arg == "--version") {
return version();
}
if(arg == "-i" || arg == "--in") {
return read_text(clip);
}
if(arg == "-o" || arg == "--out") {
std::cout << clip.paste();
return EXIT_SUCCESS;
}
if(arg == "-f") {
if(i + 1 < argc) {
return read_file(clip, args[i + 1]);
}
return error("no input file given");
}
auto&& pos = arg.find("--file");
if(pos == 0) {
// len(--file) == 6
if(i + 1 < argc && arg.size() == 6) {
return read_file(clip, args[i + 1]);
}
else if(arg[6] == '=') {
return read_file(clip, arg.substr(7));
}
return error("no input file given");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment