Skip to content

Instantly share code, notes, and snippets.

@tdulcet
Last active January 4, 2019 09:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tdulcet/819821ca69501822ad3f84a060c640a0 to your computer and use it in GitHub Desktop.
Save tdulcet/819821ca69501822ad3f84a060c640a0 to your computer and use it in GitHub Desktop.
Word wrap based on the current width of the user's terminal. Supports Unicode characters. Contains one C/C++ and two C++ solutions.
// Copyright © 2018 Teal Dulcet
// Compile: g++ -Wall -g -O3 -o wrap wrap.cpp
// Run: ./wrap
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <cctype>
#include <cstdio>
#include <cwchar>
#include <clocale>
#include <sys/ioctl.h>
#include <unistd.h>
using namespace std;
// Number of columns needed to represent the string
// Adapted from: https://stackoverflow.com/a/31124065
int strcol(const char *const str)
{
size_t length = strlen(str);
for (size_t i = 0; i < length; ++i)
if (iscntrl(str[i]))
{
cerr << "\nError! Control character in string.\n";
cout << "Control character: " << (int)str[i] << "\n";
}
length = mbstowcs(NULL, str, 0);
if (length == (size_t)-1)
{
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
exit(1);
}
++length;
wchar_t *wcstring = new wchar_t[length];
if (mbstowcs(wcstring, str, length) == (size_t)-1)
{
if (wcstring != NULL)
delete[] wcstring;
cerr << "\nError! mbstowcs failed. Invalid multibyte character.\n";
exit(1);
}
int width = wcswidth(wcstring, length);
if (width == -1)
{
cerr << "\nError! wcswidth failed. Nonprintable wide character.\n";
exit(1);
}
if (wcstring != NULL)
delete[] wcstring;
return width;
}
// C++ solution 1: shorter but does not handle new lines and tabs
// Adapted from: https://rosettacode.org/wiki/Word_wrap#C.2B.2B
string wrap1(const char *const text, const size_t line_length)
{
istringstream words(text);
ostringstream wrapped;
string word;
if (getline(words, word, ' '))
{
wrapped << word;
size_t space_left = line_length - strcol(word.c_str());
while (getline(words, word, ' '))
{
size_t width = strcol(word.c_str());
if (space_left < width + 1)
{
wrapped << '\n'
<< word;
space_left = line_length - width;
}
else
{
wrapped << ' ' << word;
space_left -= width + 1;
}
}
}
return wrapped.str();
}
// C++ solution 2: longer but handles new lines and tabs
// Adapted from: https://stackoverflow.com/a/42016346 and https://stackoverflow.com/a/13094734
string wrap2(const char *const str, const size_t line_length)
{
char words[strlen(str) + 1];
strcpy(words, str);
string wrapped;
size_t index = 0;
size_t linelen = 0;
while (words[index] != '\0')
{
if (words[index] == '\n')
{
linelen = 0;
}
else if (isspace(words[index]))
{
size_t tempindex = index + 1;
size_t templinelen = linelen;
while (!isspace(words[tempindex]) and words[tempindex] != '\0')
{
++templinelen;
++tempindex;
}
char temp[templinelen + 1];
strncpy(temp, words + (index - linelen), templinelen);
temp[templinelen] = '\0';
size_t width = strcol(temp);
// if(width != templinelen)
// cout << width << " " << templinelen << endl << temp << endl;
if (width >= line_length)
{
words[index] = '\n';
linelen = 0;
}
}
if (words[index] == '\t')
linelen += 8 - (linelen % 8);
else if (words[index] != '\n')
++linelen;
++index;
}
wrapped = words;
return wrapped;
}
// C/C++ solution
void wrap3(const char *const str, char *wrapped, const size_t line_length)
{
strcpy(wrapped, str);
size_t index = 0;
size_t linelen = 0;
while (wrapped[index] != '\0')
{
if (wrapped[index] == '\n')
{
linelen = 0;
}
else if (isspace(wrapped[index]))
{
size_t tempindex = index + 1;
size_t templinelen = linelen;
while (!isspace(wrapped[tempindex]) and wrapped[tempindex] != '\0')
{
++templinelen;
++tempindex;
}
char temp[templinelen + 1];
strncpy(temp, wrapped + (index - linelen), templinelen);
temp[templinelen] = '\0';
size_t width = strcol(temp);
// if(width != templinelen)
// cout << width << " " << templinelen << endl << temp << endl;
if (width >= line_length)
{
wrapped[index] = '\n';
linelen = 0;
}
}
if (wrapped[index] == '\t')
linelen += 8 - (linelen % 8);
else if (wrapped[index] != '\n')
++linelen;
++index;
}
}
int main()
{
// Adapted from: https://stackoverflow.com/a/23370070
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
cout << "Locale:\t" << setlocale(LC_CTYPE, "") << "\n\n";
// Text from https://malware.oregonctf.org/
// C++ solution 1
cout << wrap1("(From overthewire.org) When pointers are corrupted from format string vulnerabilities and heap overflows, an adversary can inject arbitrary input into critical parts of a process's memory. One such area for corruption is the procedure link table: a table of function pointers that support dynamically linked library calls. The table is filled in at load time to support run-time code relocation and is often left writeable. In this level, you are allowed one arbrtrary write to an arbitrary memory location between 0x0 and 0xff000000 to unlock the program. We have added a call to sleep() that you may hijack. To do so, use objdump\" or \"gdb\" to find its PLT entry, the memory location to overwrite and the address of the function to execute instead. We have included the source code for you to peruse. Note that the password will be read in using: scanf(\"\%x \%x\");", w.ws_col) << "\n\n";
// C++ solution 2
cout << wrap2("(From overthewire.org) When pointers are corrupted from format string vulnerabilities and heap overflows, an adversary can inject arbitrary input into critical parts of a process's memory. One such area for corruption is the procedure link table: a table of function pointers that support dynamically linked library calls. The table is filled in at load time to support run-time code relocation and is often left writeable. In this level, you are allowed one arbrtrary write to an arbitrary memory location between 0x0 and 0xff000000 to unlock the program. We have added a call to sleep() that you may hijack. To do so, use objdump\" or \"gdb\" to find its PLT entry, the memory location to overwrite and the address of the function to execute instead. We have included the source code for you to peruse. Note that the password will be read in using: scanf(\"\%x \%x\");\n\n", w.ws_col);
// C/C++ solution
const char str[] = "(From overthewire.org) When pointers are corrupted from format string vulnerabilities and heap overflows, an adversary can inject arbitrary input into critical parts of a process's memory. One such area for corruption is the procedure link table: a table of function pointers that support dynamically linked library calls. The table is filled in at load time to support run-time code relocation and is often left writeable. In this level, you are allowed one arbrtrary write to an arbitrary memory location between 0x0 and 0xff000000 to unlock the program. We have added a call to sleep() that you may hijack. To do so, use objdump\" or \"gdb\" to find its PLT entry, the memory location to overwrite and the address of the function to execute instead. We have included the source code for you to peruse. Note that the password will be read in using: scanf(\"\%x \%x\");\n\n";
char wrapped[strlen(str) + 1];
wrap3(str, wrapped, w.ws_col);
printf("%s", wrapped);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment