Small snippets of code that I refer to in my daily work.
These assume that you are using C++14 and boost.
... like auto s = "this is a std::string"s;
using namespace std::literals;
... like auto microseconds = 1000us;
using namespace std::chrono_literals;
std::regex requires at least C++11. CTRE requires at least C++17.
#include <regex>
if (std::regex_match(string,std::regex("[a-zA-Z]*"))) {
cout << "Matches\n";
}
#include <ctre.hpp>
using namespace ctre::literals;
if ("[a-zA-Z]*"_ctre.match(string)) {
cout << "Matches\n";
}
#include <regex>
const auto result = regex_replace(str,std::regex("<"),"<");
#include <regex>
const auto str = "Jul-18-2017";
std::smatch match;
if (std::regex_search(str,match,std::regex("([a-zA-Z]*)-([0-9]*)-([0-9]*)"))) {
std::cout << "Month: " << match[1] << ", day: " << match[2] << ", year: " << match[3] << "\n";
} else {
// No match
}
#include <ctre.hpp>
using namespace ctre::literals;
const auto str = "Jul-18-2017";
if (const auto match="([a-zA-Z]*)-([0-9]*)-([0-9]*)"_ctre.match(str)) {
std::cout << "Month: " << match.get<1>() << ", day: " << match.get<2>() << ", year: " << match.get<3>() << "\n";
} else {
// No match
}
#include <boost/tokenizer.hpp>
auto const tokens = boost::tokenizer<boost::char_separator<char>>(mystring,
boost::char_separator<char>("\n"));
for (std::string const &t : tokens) {
std::cout << t << std::endl;
}
#include <boost/algorithm/string.hpp>
std::string const untrimmed = ...;
auto const trimmed = boost::trim_copy(untrimmed);
#include <fstream>
auto ifs = std::ifstream(file);
auto const data = std::string(
std::istreambuf_iterator<char>(ifs),
std::istreambuf_iterator<char>()
);
auto in = std::istream(...);
auto out = std::ostream(...);
out << in.rdbuf();
#include <fstream>
std::string longstr;
{
auto ifs = std::ifstream("/dev/urandom",std::ios::binary);
auto isi = std::istream_iterator<char>(ifs);
std::copy_n(isi,
10'000'000,
std::insert_iterator<std::string>(longstr,longstr.begin()));
}
#include <boost/filesystem.hpp>
boost::filesystem::create_directories(boost::filesystem::path(file).parent_path());
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>
std::string dir = ...;
for(auto const &f: boost::make_iterator_range(boost::filesystem::directory_iterator(dir))) {
auto const file = f.path().string();
std::cout << "Found file: " << file << std::endl;
}
#include <boost/date_time/posix_time/posix_time.hpp>
auto const tm = boost::posix_time::to_tm(boost::posix_time::second_clock::local_time());
auto request = boost::network::http::client::request("http://...");
request << boost::network::header("Connection","close");
auto const result = body(boost::network::http::client().get(request));
Supports both GET and POST. Not complete code, just for illustration.
#include <curl/curl.h>
size_t WriteFct(void* contents,size_t size,size_t nmemb,void* userp) {
std::string *const buf = static_cast<std::string*>(userp);
*buf += std::string(static_cast<char*>(contents),size*nmemb);
return size * nmemb;
}
void LoadWithCurl()
{
const auto curl = curl_easy_init();
if (!curl) {
throw std::runtime_error("Error initializing the curl context");
}
// Close the curl session when done
BOOST_SCOPE_EXIT_ALL(curl) {
curl_easy_cleanup(curl);
};
// Configure the curl session
std::string buf;
char err[CURL_ERROR_SIZE] = "";
curl_easy_setopt(curl,CURLOPT_URL,url.c_str());
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,WriteFct);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,static_cast<void*>(&buf));
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,err);
// Set the POST data (and activate POST) if requested by the caller
if (postdata) {
// Note: CURLOPT_POSTFIELDSIZE is restricted to 2 GB or less.
curl_easy_setopt(curl,CURLOPT_POSTFIELDSIZE,postdata->size());
curl_easy_setopt(curl,CURLOPT_POSTFIELDS,postdata->data());
}
// Perform the actual HTTP query
const auto res1 = curl_easy_perform(curl);
if (res1!=CURLE_OK) {
throw std::runtime_error("Error accessing " + url + ": " + (err[0] ? err : curl_easy_strerror(res1)));
}
// Check the HTTP result status
long status = -1;
const auto res2 = curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&status);
if (res2!=CURLE_OK) {
throw std::runtime_error("Error getting HTTP result status: "s + curl_easy_strerror(res2));
}
)
#include <iostream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
// Output (file opened for writing)
int fd = ...;
boost::iostreams::file_descriptor_sink snk(fd,boost::iostreams::close_handle);
boost::iostreams::stream<boost::iostreams::file_descriptor_sink> os(snk);
os << "Hello World\n";
// Input (file opened for reading)
int fd = ...;
boost::iostreams::file_descriptor_source src(fd,boost::iostreams::close_handle);
boost::iostreams::stream<boost::iostreams::file_descriptor_source> is(src);
is >> myvariable;
Download the Boost source to your home directory, then:
$ chmod a+wrx /usr/local/lib /usr/local/include
$ rm -f /usr/local/lib/*boost*
$ rm -rf /usr/local/include/boost
$ mkdir -p boost
$ cd boost
$ rm -fr build
$ mkdir build
$ rm -fr boost_*
$ tar xzf ~/boost_*.tar.gz
$ cd boost_*
$ ./bootstrap.sh --without-libraries=python
$ ./b2 --build-dir=~/boost/build $MINUSJ variant=release link=static threading=multi runtime-link=static install
It's surprisingly easy.
$ cd
$ mkdir gcc
$ cd gcc
$ wget ftp://ftp.fu-berlin.de/unix/languages/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.gz
$ tar xzf gcc-9.1.0.tar.gz
$ cd gcc-9.1.0
$ contrib/download_prerequisites
$ cd ~/gcc
$ mkdir build
$ cd build
$ ../gcc-9.1.0/configure --prefix=$HOME/gcc/install --disable-multilib
$ make
$ make install
$ ~/gcc/install/bin/g++ --version
g++ (GCC) 9.1.0
$ sudo update-alternatives --install /usr/bin/gcc gcc $HOME/gcc/install/bin/gcc 60 --slave /usr/bin/g++ g++ $HOME/gcc/install/bin/g++
$ sudo update-alternatives --config gcc
$ gcc --version
gcc (GCC) 9.1.0
$ g++ --version
g++ (GCC) 9.1.0
To run executables built with gcc 9 (unless linked statically):
$ export LD_LIBRARY_PATH=$HOME/gcc/install/lib64:$LD_LIBRARY_PATH
$ cd /opt
$ wget https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5.tar.gz
$ tar xzf cmake-3.14.5.tar.gz
$ cd cmake-3.14.5
$ mkdir build
$ cd $_
$ cmake ..
$ make -j8
$ sudo mkdir -p -m 777 /usr/local/doc /usr/local/share
$ make install
$ cmake --version
cmake version 3.14.5
If there's no cmake already installed, do the following instead of invoking cmake (in the source directory, don't create a build directory):
$ ./bootstrap -- -DCMAKE_BUILD_TYPE:STRING=Release
More info: https://cmake.org/install/
git config --global alias.godlog "log --graph --oneline --decorate"
This allows you to use "git diff" with Microsoft Office (Word, PowerPoint) and Libre Office (Writer, Calc, Impress) files stored in a git repository. The trick is to tell git how to extract plain text from these files, on which the regular diff can be used.
Install the conversion tools:
$ sudo apt install unoconv catdoc
Optionally, only needed for .pptx
files:
$ pip install python-pptx
- Copy
git-pptx-textconv.py
from this repo to a location of your choice and make it executable
Add the following to ~/.gitconfig
:
[diff "doc"]
textconv=catdoc
[diff "odt"]
textconv=odt2txt
[diff "odp"]
textconv=odp2txt
[diff "ods"]
textconv=ods2txt
[diff "ppt"]
textconv=catppt
[diff "pptx"]
textconv=/location/of/git-pptx-textconv.py
Add the following to ~/.config/git/attributes
(or, alternatively, to the .gitattributes
file in the project root):
*.doc diff=doc
*.odp diff=odp
*.ods diff=ods
*.odt diff=odt
*.ppt diff=ppt
*.pptx diff=pptx
If git diff
displays the following error:
Error: Unable to connect or start own listener. Aborting.
fatal: unable to read files to diff
then type unoconv -l
and retry.
More information:
- http://www-verimag.imag.fr/~moy/opendocument/
- https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes ("Diffing Binary Files" section)
- https://stackoverflow.com/a/32259984/14667736 (original source of git-pptx-textconv.py, I only ported it to Python 3)
- https://stackoverflow.com/questions/52873519/how-can-i-get-useful-git-diff-of-files-saved-by-libre-office-writer-with-output/65733260
... that is created from a Libre Office document which is managed in git as described in the previous section, using the tag-based version number generated by git describe
. Tested with Libre Office 5 in Linux.
Preparation (once per document):
- Open the document in LibreOffice Writer
- Move cursor to where the version number is to be displayed
- Insert → Field → More fields ...
- Variables → Set variable, Name: version, Value: 0.0, Format: Text, Insert, Close
- To show the version number elsewhere: Insert → Field → More fields ... → Variables → Show variable, version, Insert, Close
- Close and save the document
- Add/commit the document to git
To convert the document into a PDF, replacing the "0.0" placeholder by the current git version number:
$ odt2pdf -o myname.pdf -F version=$(git describe --dirty --always) filename.odt
About tag-based git version numbers: https://git-scm.com/docs/git-describe
... and be as portable as possible by switching off stuff like GNU language extensions.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_EXTENSIONS OFF)
cmake_minimum_required (VERSION 3.5)
project (myproject CXX)
find_package (Threads REQUIRED)
add_executable (myproject ...)
target_link_libraries (myproject Threads::Threads)
More: https://stackoverflow.com/questions/1620918/cmake-and-libpthread
set (EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/build")
find_program (CCACHE_FOUND ccache)
if (CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
endif (CCACHE_FOUND)
Where "Shell" means bash, or something sufficiently compatible.
Show the last command's exit status in the shell prompt, and show the prompt with a dark background to make it stand out better. When in a git repository, show the current git status: a cross if something needs to be committed, an up arrow if something needs to be pushed, a down arrow when something can be pulled, three stacked horizontal lines if there's a shash, a check mark if everything is clean.
Put the following into your .profile
or .bashrc
.
gitstatus() {
if [ "$1" = "--color" ];then
local RED=$(tput setaf 1)
local BLU=$(tput setaf 6)
local GRN=$(tput setaf 2)
local OFF=$(tput sgr0)
else
local RED=""
local BLU=""
local GRN=""
local OFF=""
fi
local S
S=$(LANG=C git status -sb --porcelain 2>/dev/null) || return
if [[ $S =~ [[:cntrl:]][^#] ]];then
echo "${RED}×${OFF} "
elif [[ $S =~ ^##.*\[behind ]];then
echo "${BLU}↓${OFF} "
elif [[ $S =~ ^##.*\[ahead ]];then
echo "${BLU}↑${OFF} "
elif git stash list | grep -q .;then
echo "${BLU}≡${BLU} "
else
echo "${GRN}✓${OFF} "
fi
}
gits() {
local G
find ${*:-.} -type d -name .git 2>/dev/null \
| while read G;do
local D=$(dirname "$G")
(cd "$D" >/dev/null && git remote update &>/dev/null && echo "$(gitstatus --color)$D")
done
}
PS1BEFORE=$(tput sgr0)$(tput rev)$(tput setaf 4)
PS1AFTER=$(tput sgr0)
PS1='\[$PS1BEFORE\]$? [\h:\w]\[$PS1AFTER\] $(gitstatus)\$ '
This also defines the gits
command which recursively searches the current directory (or directories you specify on the command line) for git repositories and displays their status (cross, up/down arrow, check mark as described above).
$ gits
↑ ./afl-demo
✓ ./cloud-backup
✓ ./cmake-hello-world
✓ ./ecs
↑ ./helloworld
✓ ./itunes-in-nextcloud
× ./snippets
↓ ./ThreadPool
✓ ./version
PS1="\[\e]0;\h:\w\a\]$PS1"
export HISTFILE="$HOME/.bash-history"
export HISTFILESIZE=
export HISTSIZE=
Changing the history file name from the default .bash_history to something else (here, by using a dash instead of an underscore, but could be anything) prevents non-login shells (that use the default history size) from deleting our history.
Requires gawk (the Gnu implementation of awk, e. g. as Linux has it).
$ gawk 'BEGIN {print systime()}'
1497429720
$ gawk 'BEGIN {print mktime("2017 06 14 10 42 00")}'
1497429720
$ gawk 'BEGIN {print strftime("%F %T %Z",1497429720)}'
2017-06-14 10:42:00 CEST
$ gawk 'BEGIN {print strftime("%F %T %Z",1497429720,1)}'
2017-06-14 08:42:00 GMT
Make key pair:
$ openssl req -newkey rsa:2048 -new -nodes -x509 -days 36500 -out cert.pem -keyout key.pem
cert.pem
is the certificate file (public key), used for encryption. key.pem
is the private key file, used for decryption.
Encrypt:
$ openssl smime -encrypt -aes256 -binary -outform DER cert.pem <cleartext.dat >ciphertext.dat
Decrypt:
$ openssl smime -decrypt -inform DER -inkey key.pem <ciphertext.dat >cleartext.dat
Show contents of a pem file:
$ openssl x509 -in filename.pem -text
Replace 11 and 22 with the range of pages you want to extract.
With pdftk:
$ pdftk your-input-file.pdf cat 11-22 output your-output-file.pdf
pdftk can extract arbitrary collections of pages (e. g., use cat 1 3-5 8
to extract pages 1, 3, 4, 5, and 8).
With Ghostscript:
$ gs -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -dSAFER \
-dFirstPage=11 \
-dLastPage=22 \
-sOutputFile=your-output-file.pdf \
your-input-file.pdf
:set ff=unix
which is annoying as hell and completely different from the way Unix programs classically work.
In shell profile:
export SYSTEMD_PAGER=cat
Then:
$ sudo visudo
Add the following line in the "Defaults" section:
Defaults env_keep += "SYSTEMD_PAGER"
Make your mouse wheel work like on a Mac: Roll up to scroll up, roll down to scroll down.
Put the following into /usr/share/X11/xorg.conf.d/20-natural-scrolling.conf, then reboot:
Section "InputClass"
Identifier "Natural Scrolling"
MatchIsPointer "on"
MatchDevicePath "/dev/input/event*"
Option "VertScrollDelta" "-1"
Option "HorizScrollDelta" "-1"
Option "DialDelta" "-1"
EndSection
If this doesn't work, try:
$ xinput set-prop 9 275 1
9
and 275
are just examples, find the actual values as follows.
First, the 9
is the id
of your mouse device, to be found like this:
$ xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ Logitech USB-PS/2 Optical Mouse id=9 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Power Button id=8 [slave keyboard (3)]
↳ Eee PC WMI hotkeys id=10 [slave keyboard (3)]
↳ AT Translated Set 2 keyboard id=11 [slave keyboard (3)]
Once you got the 9
, find the 275
like this:
$ xinput list-props 9 | grep -i natural
libinput Natural Scrolling Enabled (275): 0
libinput Natural Scrolling Enabled Default (276): 0
Sources:
- https://wiki.archlinux.org/index.php/Libinput#Natural_scrolling
- https://kofler.info/natural-scrolling-mit-dem-mausrad/#more-1956
Make your machine start up and shut down like a real computer.
In /etc/default/grub
, remove quiet splash
from GRUB_CMDLINE_LINUX_DEFAULT
, so it's
GRUB_CMDLINE_LINUX_DEFAULT=""
Uncomment GRUB_GFXMODE
and set it to one one more resolutions supported by your monitor, followed by auto
, for example
GRUB_GFXMODE="1920x1080,640x480,auto"
Then:
$ sudo update-grub
Reboot and enjoy.
Sources:
- https://askubuntu.com/questions/25022/how-to-enable-boot-messages-to-be-printed-on-screen-during-boot-up
- http://www.subdude-site.com/WebPages_Local/RefInfo/Computer/Linux/BootMessages_andGrub2/BootMessages_andGrub2.htm
- https://askubuntu.com/questions/103516/grub2-use-maximum-detected-resolution#142332
- https://www.gnu.org/software/grub/manual/grub/html_node/gfxmode.html
Access the files in your Nextcloud without syncing them to your harddisk, using Nextcloud's WebDAV interface. Doesn't require disk space to store your Nextcloud files locally. Doesn't use the Nextcloud client software.
Tested with Ubuntu 16.04. Will probably work with Owncloud or any other WebDAV-based file service.
The following examples assume that
mycloud.example.com
is your Nextcloud servermyname
is your Nextcloud user namemypassword
is your Nextcloud password
Preparation:
$ sudo apt install ca-certificates
$ sudo apt install davfs2
$ sudo mkdir /mnt/myname
$ sudo usermod -aG davfs2 $USER
Add the following line to /etc/fstab
:
https://mycloud.example.com/remote.php/webdav /mnt/myname davfs user,noauto 0 0
If you want read-only access (you can read your cloud files but not change them):
https://mycloud.example.com/remote.php/webdav /mnt/myname davfs user,noauto,ro,dir_mode=555,file_mode=444 0 0
Add the following to /etc/davfs2/secrets
:
/mnt/myname myname mypassword
Note: Every user on your Linux machine can mount your Nextcloud files, which may or may not be desired.
Finally, to mount your Nextcloud files:
$ sudo mount /mnt/myname
More information: https://wiki.ubuntuusers.de/WebDAV/
Using it to back up your Nextcloud: https://gitlab.com/wolframroesler/back-up-nextcloud
$ sudo add-apt-repository ppa:maarten-baert/simplescreenrecorder
$ sudo apt-get update
$ sudo apt-get install simplescreenrecorder
More: http://www.maartenbaert.be/simplescreenrecorder/
$ drutil tray eject
$ defaults write com.apple.desktopservices DSDontWriteNetworkStores true
Log off or reboot to activate.
To install software like a boss.
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew analytics off
More information: http://brew.sh
You may like:
$ brew install htop
$ brew install tree
To use the boost C++ libraries. Requires the brew
package manager desribed above.
$ brew install boost
$ ln -s /usr/local/Cellar/boost/1.67.0_1/ /usr/local/boost
And update the symlink whenever a new boost version comes out. Why don't they install in /usr/local/boost
directly like everyone else, or at least create the symlink automatically?
If you need to build different projects with different boost versions you can leave the symlink away and use an environment variable instead:
$ export BOOST_ROOT=/usr/local/Cellar/boost/1.67.0_1/
set profiling=1;
select ...;
show profile;
explain select ...;
Useful in test cases, e. g. when testing where clauses constructed from user input. Causes a lot of load in the database that makes the application hang, hogs one more more CPUs, prevents new clients from connecting, and might require a DB bounce.
SELECT something
FROM somewhere
WHERE BENCHMARK(100000000000,ENCODE('a','b'))='c';
Wolfram Rösler • wolfram@roesler-ac.de • https://gitlab.com/wolframroesler • https://twitter.com/wolframroesler • https://www.linkedin.com/in/wolframroesler/