Almost accurate float to string algorithm

On machine 12.341 results in “12.340999″. Close enough eh? Once I get this perfect, I’ll make it into a template function with specifications for making the string in ‘e’ notation.

#include <iostream>
#include <string>
#include <cmath>
#include <cstdio>

std::string ftos(float f, int precis = 6) {
	int e, i;
	std::string buf;
	int whole;
	bool neg;
	
	/* Check for nan or [-]inf */
	if (isnan(f)) return std::string("nan");
	else if (e = isinf(f)) {
		if (e < 0) return std::string("-inf");
		else return std::string("inf");
	}
	
	/* Check for negative and convert to positive */
	if (f < 0) { neg = true; f *= -1.0; }
	
	/* Extract whole number */
	for (whole = 0; f >= 1.0; f -= 1.0, whole++);
	
	/* Convert whole number to string */
	if (neg) buf.push_back('-');
	char tmp[64];
	sprintf(tmp, "%d", whole);
	buf.append(tmp);
	
	if (f == 0.0) return buf;
	buf.push_back('.');
	
	/* Loop through each floating digit in precision */
	for (i = 0; i < precis; i++) {
		if (f == 0.0) break;
		
		/* Shift next floating digit to whole number */
		f *= 10.0;
		/* Extract whole number */
		for (whole = 0; f >= 1.0; f -= 1.0, whole++);
		/* Convert to character */
		buf.push_back(whole + '0');
	}
	
	/* Fill with leading 0's for precision */
	if (f == 0.0 && i < precis)
		for (; i < precis; i++)
			buf.push_back('0');
			
	return buf;
}

int main() {
	std::cout << ftos(12.341) << std::endl;
}

Integer to string template function

Convert any integer type, to any c++ string type (char or wchar_t) using this template function:

#include <string>
#include <algorithm>
#include <iostream>

template <typename Int_T, typename Char_T>
std::basic_string<Char_T> itoa(Int_T num, int base) {
	std::basic_string<Char_T> buf;
	buf.push_back(0);
	bool neg;
	
	if (num < 0) { neg = true; num *= -1; }
	
	int i, j;
	Char_T digits[36];
	for (j = 0, i = '0'; i <= '9'; i++, j++) digits[j] = i;
	for (i = 'a'; i <= 'z'; i++, j++) digits[j] = i;
	
	do {
		buf.push_back(digits[num % base]);
		num /= base;
	} while (num != 0);
	if (neg) buf.push_back('-');
	std::reverse(buf.begin(), buf.end());
	return buf;
}

int main() {
	std::wcout << L"-12 in binary is " <<
	itoa<int, wchar_t>(-12, 2) <<
	std::endl;
}

Create iterator from static array

This class allows you to construct an iterator for any static array. This is a template iterator.

#ifndef CHAR_ITERATOR_H
#define CHAR_ITERATOR_H
#include <iterator>

template <typename T>
class char_iterator : public std::iterator<std::random_access_iterator_tag, T>
{
	T* ptr;
public:
	char_iterator() : ptr(0) {}
	char_iterator(T* p) : ptr(p) {}
	char_iterator(const char_iterator& bsi) : ptr(bsi.ptr) {}
	char_iterator<T>& operator= (const char_iterator<T>& bsi) { ptr = bsi.ptr; return *this; }
	bool operator== (const char_iterator<T>& bsi) { return ptr == bsi.ptr; }
	bool operator!= (const char_iterator<T>& bsi) { return ptr != bsi.ptr; }
	T& operator*() { return *ptr; }
	char_iterator<T>& operator++ () { ptr = &ptr[1]; return *this; }
	char_iterator<T> operator++ (int) {
		char_iterator<T> tmp(*this);
		this->operator++();
		return tmp;
	}
	char_iterator<T>& operator-- () { ptr = &ptr[-1]; return *this; }
	char_iterator<T> operator-- (int) {
		char_iterator<T> tmp(*this);
		this->operator--();
		return tmp;
	}
	T* operator-> () { return ptr; }
	char_iterator<T>& operator+= (int i) { ptr += (&ptr[1] - ptr) * i; return *this; }
	char_iterator<T> operator+ (int i) {
		char_iterator<T> tmp(*this);
		tmp += i;
		return tmp;
	}
	char_iterator<T>& operator-= (int i) { ptr -= (&ptr[1] - ptr) * i; return *this; }
	char_iterator<T> operator- (int i) {
		char_iterator<T> tmp(*this);
		tmp -= i;
		return tmp;
	}
	bool operator< (const char_iterator<T>& ci) { return ptr < ci.ptr; }
	bool operator> (const char_iterator<T>& ci) { return ptr > ci.ptr; }
	bool operator<= (const char_iterator<T>& ci) { return ptr <= ci.ptr; }
	bool operator>= (const char_iterator<T>& ci) { return ptr >= ci.ptr; }
	T& operator[] (int i) { return ptr[i]; }
	operator T* () { return ptr; }
	operator const T* () { return ptr; }
};

template <typename T>
class const_char_iterator : public std::iterator<std::random_access_iterator_tag, T>
{
	const T* ptr;
public:
	const_char_iterator() : ptr(0) {}
	const_char_iterator(const T* p) : ptr(p) {}
	const_char_iterator(const const_char_iterator& bsi) : ptr(bsi.ptr) {}
	const_char_iterator<T>& operator= (const const_char_iterator<T>& bsi) { ptr = bsi.ptr; return *this; }
	bool operator== (const const_char_iterator<T>& bsi) { return ptr == bsi.ptr; }
	bool operator!= (const const_char_iterator<T>& bsi) { return ptr != bsi.ptr; }
	T operator*() { return *ptr; }
	const_char_iterator<T>& operator++ () { ptr = ptr[i]; return *this; }
	const_char_iterator<T> operator++ (int) {
		const_char_iterator<T> tmp(*this);
		this->operator++();
		return tmp;
	}
	const_char_iterator<T>& operator-- () { ptr = ptr[-1]; return *this; }
	const_char_iterator<T> operator-- (int) {
		const_char_iterator<T> tmp(*this);
		this->operator--();
		return tmp;
	}
	T* operator-> () { return ptr; }
	const_char_iterator<T>& operator+= (int i) { ptr = (&ptr[1] - ptr) * i; return *this; }
	const_char_iterator<T> operator+ (int i) {
		const_char_iterator<T> tmp(*this);
		tmp += i;
		return tmp;
	}
	const_char_iterator<T>& operator-= (int i) { ptr = (&ptr[1] - ptr) * i; return *this; }
	const_char_iterator<T> operator- (int i) {
		const_char_iterator<T> tmp(*this);
		tmp -= i;
		return tmp;
	}
	bool operator< (const const_char_iterator<T>& ci) { return ptr < ci.ptr; }
	bool operator> (const const_char_iterator<T>& ci) { return ptr > ci.ptr; }
	bool operator<= (const const_char_iterator<T>& ci) { return ptr <= ci.ptr; }
	bool operator>= (const const_char_iterator<T>& ci) { return ptr >= ci.ptr; }
	T operator[] (int i) { return ptr[i]; }
	operator const T* () { return ptr; }
};

#endif
 

Example:

#include "char_iterator.h"
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;

int main() {
    char s[256];
    strcpy(s, "hello world!");
    replace(char_iterator<char>(s), char_iterator<char>(s + strlen(s)), 'l', 'q');
    cout << s << endl;
        
}
 

PROTIP: For wide character strings, you can use char_iterator(wchar_t*).
Also there’s const_char_iterator, which works on constant arrays.

New C++ library project

I’ve decided that I’m starting a new c++ library project instead of a 2nd version of AXCEL. It’s called CodeTherapy and is hosted at github:

https://github.com/Jakash3/codetherapy

It’s currently undergoing development. But you can watch my progress as I upload and modify source files to the repo.

The stream classes will be redesigned. Instead of having pure virtual functions in the stream classes, they will be virtual functions with a default behavior of failing and setting the last error associated with the object to ENOTSUP (Not supported). Derived classes of stream will have to at least implement getc or putc member functions while functions like seek, tell, flush, peek, and sync will be optional to implement. The programmer then can override readable, writable, seekable, buffered, and peekable boolean functions which specify which set of optional functions are supported.

The string and bytes classes will be integrated with the STL.

My goal is to have the library handle code like this:

stream s = fopen("foo.txt", "w");
s.puts("hello world!");
s.close();
...
lnstream s = tcp::connect("www.google.com", "80");
s << "GET " << resource << " HTTP/1.1\r\nHost: www.google.com\r\n\r\n";
string header = s.drink("\r\n\r\n");
...
s.close();

String to floating point decimal

#include <iostream>
#include <cctype>
#include <cstdlib>
using namespace std;

/*
 *	stof by Jakash3
 *	Converts a string to floating point decimal using
 *	specified floating point type template
 *	The string should be in the form:
 *	[+-]?[0123456789].([.][0123456789]+)?[ ]*([eE][+-]?[0123456789]+)?
 *
 *	Example strings:
 *	25, 3.5, 3.500, 3.5e6, 3.5 e-5, 3.5E5, 3.5E-4, 3.5 e+8
 */
template <typename T>
T stof(const char* s) {
	T val = 0;			/* Integer part */
	T frac = 0;			/* Fractional part */
	bool neg = false;	/* Sign flag */
	
	/* Skip whitespace */
	while (isspace(*s)) s++;
	
	/* Check for sign */
	if (*s == '-') { neg = true; s++; }
	else if (*s == '+') s++;
	
	/* Read integer part */
	while (isdigit(*s))
		val = val * 10 + (*(s++) - '0');
	
	/* Read fractional part */	
	if (*s == '.') {
		T q;
		for (s++; isdigit(*s); s++); s--;
		do {
			q = *s - '0';
			frac = frac / 10 + q / 10;
		} while (isdigit(*(--s)));
		while (isdigit(*(++s))) s++;
	}
	
	/* Skip whitespace */
	while (isspace(*s)) s++;
	
	/* Combine integer and fractional part, and apply sign */
	val += frac;
	if (neg) val *= -1;
	
	/* Process E notation */
	if (*s == 'e' || *s == 'E') {
		int j = atoi(++s);
		if (j == 0) return val;
		for (int i = 0; i != j; (j > 0) ? i++ : i--)
			(j > 0) ? val *= 10 : val *= -10;
	}
	
	return val;
}

int main() {
	float f;
	string s;
	cout << "Enter float: ";
	getline(cin, s);
	cout << "You entered " << stof<float>(s.c_str()) << endl;
}

My updated string to int function

#include <iostream>
#include <string>
#include <cstring>
#include <cctype>
using namespace std;

/* 
 * stoi by Jakash3
 * Converts a string to integer using specified base
 * and integer type template.
 * if base is 0, the base is then determined by a 0x, 0
 * or no prefix in the string.
 */
template <typename T>
T stoi(const char* s, int base) {
	T num = 0;
	bool negative = false;
	static const char digits[] = "0123456789abcdefghijklmnopqrxtuvwxyz";
	
	/* Skip leading whitespace */
	while (isspace(*s)) s++;
	
	/* Check for sign */
	if (*s == '-') { negative = true; s++; }
	else if (*s == '+') s++;
	
	/* Check for base prefix */
	if (*s == '0') {
		s++;
		if (*s == 'x' || *s == 'X') {
			if (base == 0) base = 16;
			else if (base != 16) return 0;
			s++;
		} else if (isdigit(*s)) {
			if (base == 0) base = 8;
		} else if (*s == 0) return 0;
	} else if (*s == 0) return 0;
	else if (base == 0) base = 10;
	
	/* Loop through each digit */
	for (int digit; *s; s++) {
	
		/* Look for digit in the list of digits */
		const char *where = strchr(digits, tolower(*s));
		
		/* Check for valid digit */
		if (where == NULL) break;
		digit = where - digits;
		if (digit >= base) break;
		
		/* Shift the number and add the new digit */
		num  = num * base + digit;
	}
	
	/* Handle negative numbers */
	if (negative) return -num;
	
	/* Done */
	return num;
}

int main() {
	string s;
	cout << "Enter a number: ";
	getline(cin, s);
	cout << stoi<int>(s.c_str(), 0) << endl;
}

conio.h for Linux

For those of you who like to make command-line RPGs in C using conio.h, but disappointed because conio.h library is not available in Linux. Your wait is over!
I have included a modern GNU/Linux implementation of the old MS-DOS conio.h library. Included functions are getch, getche, kbhit, gotoxy, and clrscr.

Header:

/*
 *	terminal_io.h
 *	Author: Jakash3
 *	Date: 22 Dec 2011
 *	Some conio.h functions for GNU/Linux
 */
#ifndef TERMINAL_IO
#define TERMINAL_IO

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <sys/select.h>

// Turns terminal line buffering on or off
void terminal_lnbuf(int yn);

// Turns terminal keyboard echo on or off
void terminal_echo(int yn);

// Get next immediate character input (no echo)
int getch();

// Get next immediate character input (with echo)
int getche();

// Check if a key has been pressed at terminal
int kbhit();

// Set cursor position
void gotoxy(int x, int y);

// Clear terminal screen and set cursor to top left
void clrscr();

#endif

Source:
#include "terminal_io.h"

void terminal_lnbuf(int yn) {
	struct termios oldt, newt;
	tcgetattr(0, &oldt);
	newt = oldt;
	newt.c_lflag &= (yn ? ICANON : ~ICANON);
	tcsetattr(0, TCSANOW, &newt);
}

void terminal_echo(int yn) {
	struct termios oldt, newt;
	tcgetattr(0, &oldt);
	newt = oldt;
	newt.c_lflag &= (yn ? ECHO : ~ECHO);
	tcsetattr(0, TCSANOW, &newt);
}

void gotoxy(int x, int y) { printf("\x1B[%d;%df", y, x); }

void clrscr() { printf("\x1B[2J\x1B[0;0f"); }

int getch() {
	register int ch;
	terminal_lnbuf(0);
	terminal_echo(0);
	ch = getchar();
	terminal_lnbuf(1);
	terminal_echo(1);
	return ch;
}

int getche() {
	register int ch;
	terminal_lnbuf(0);
	ch = getchar();
	terminal_lnbuf(1);
	return ch;
}

int kbhit() {
	register int ret;
	fd_set fds;
	terminal_lnbuf(0);
	terminal_echo(0);
	struct timeval tv;
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	FD_ZERO(&fds);
	FD_SET(0, &fds);
	select(1, &fds, 0, 0, &tv);
	ret = FD_ISSET(0, &fds);
	terminal_lnbuf(1);
	terminal_echo(1);
	return ret;
}

Updated 4chan thread downloader

This is updated for the version of AXCEL which was uploaded on 11/12/2011. Compiled windows binary included.
Download: http://www.mediafire.com/?jyjjq712nqp5l2f

Code:

#include "axcel/axcel.h"
use fs;
use net;

struct fcpost {
	string author;
	string img;
	long double size;
	ulong height;
	ulong width;
};

int main(int argc, char** argv) {
	unless (argc > 1)
		die (
			"4chan Thread Downloader by Jakash3\n"
			"Download all images from a thread\n"
			"Usage: %s THREAD_URL [-o dir] [-s max] [-d height width] "
			"[-a author]\n\n"
			"-o dir            Output directory\n"
			"-s max            Maximum size in kilobytes\n"
			"-d height width   Maximum height and width\n"
			"-a author         Only download images from this author\n",
			argv[0]
		);
	
	fcpost post;
	socket::tcp sock;
	http::header head;
	http::response response;
	string s = argv[1], t, u;
	file f;
	ulong i, j, k;
	data d;
	
	long double max = 0;
	ulong height = 0, width = 0;
	string author;

	for (i = 2; i < argc; i++) {
		if (eq(argv[i], "-o")) cd(argv[++i]);
		else if (eq(argv[i], "-s")) max = stof<long double>(argv[++i]);
		else if (eq(argv[i], "-a")) author = argv[++i];
		else if (eq(argv[i], "-d")) {
			height = stoi<ulong>(argv[++i]);
			width = stoi<ulong>(argv[++i]);
		}
	}
	s = s.munch("http://").burn('#');
	unless (sock.connect(s.burn('/'), "80")) {
		con.put("Failed to connect: ").echo(sock.error());
		return 1;
	}
	sock <<
		"GET /" << s.slurp('/') << " HTTP/1.1\r\n"
		"Host: " << s.burn('/') << "\r\n\r\n";
	response = sock.drink("\r\n");
	head = sock.drink("\r\n\r\n");

	con.put(response);
	if (response.code != 200) { sock.close(); return 1; }
	s = sock.drink("</html>");
	sock.close();

	for (s.rewind(), t = s.gets(); !t.ends("</html>"); t = s.gets()) {
		if (t.str("<a href=\"http://images.4chan.org") == -1) continue;

		post.author = t.slurp("<span class=\"commentpostername\">").burn('<');
		post.img = t.slurp("<span class=\"filesize\">").slurp("<a href=\"").burn('\"');
		u = t.slurp("<span class=\"filesize\">").slurp("-(");
		if (u.slurp(' ').starts("KB")) post.size = stof<long double>(u.burn(' '));
		else if (u.slurp(' ').starts("MB")) post.size = stof<long double>(u.burn(' ')) * 1024;
		else post.size = 0;
		post.height = atoi(u.slurp(", "));
		post.width = atoi(u.slurp('x'));
		
		if (max) if (post.size > max) continue;
		if (height) if (post.height > height) continue;
		if (width) if (post.width > width) continue;
		unless (author.empty()) if (post.author != author) continue;
		
		unless (f.open(post.img.rslurp('/'), "wb")) {
			con <<
				"Error opening " << post.img.rslurp('/') << " for writing: " <<
				f.error() << "\n";
			return 1;
		}
		sock = socket::tcp();
		unless (sock.connect("images.4chan.org", "80")) {
			con << "Error connecting to images.4chan.org: " << sock.error() << "\n";
			return 1;
		}

		u.clear();
		con.put(post.img);
		sock <<
			"GET " << post.img.slurp(".org") << " HTTP/1.1\r\n"
			"Host: images.4chan.org\r\n\r\n";
		response = sock.drink("\r\n");
		if (response.code != 200) con.echo(" FAILED");
		else con.echo();
		head = sock.drink("\r\n\r\n");
		j = atoi((string)head["Content-Length"].var());
		con << "Downloaded 0 / " << j / 1024 << " KB";
		for (i = 0, k = 1024; i < j; i++) {
			f.putc(sock.getc());
			if (i == k) {
				con.putcr();
				con << "Downloaded " << i / 1024 <<
				"/" << j / 1024 << " KB";
				k += 1024;
			}
		}
		con.echo();
		con.echo();
		f.close();
		sock.close();
	}
	return 0;
}

A short story

This is my first non-coding post. This was a class assignment, supposed to be my made up greek myth story. Even though I got off track from having it be a greek myth, people still thought it was pretty good so I will share it. The title is “Transfer”:

Chris was nothing more than what appeared to be an average boring highschool loner. He lived around an urban city, where life moves fast in accordance to the state of trance everybody goes through from weekday to weekday. The alarm goes off; the sound of bustling cars, pedestrians, and the various music that comes accompanied with hologram street advertisements starts playing. Chris grudgingly gets up, selects his outfit for the day from the menu displayed on his mirror, and after a few more preparations he’s off to school. As soon as the streetlight gave the signal, everybody including Chris started to walk to the other side of the street; everybody facing forward, walking at the same pace, having the same blank expression on all their faces.

However, when Chris got to the other side he came to realize that he’s more late than he thought and decided to take a shortcut through an unfamiliar area, where an abandoned factory is located. As it became apparent that he was breaking off his daily trail, his pet hologram which was part of his reality augmentation vision spawned into his view. These pets are assigned to every student in the district, their artificial intelligence are based on the assigned student’s schedule. Whenever the student gets off track from their destination, these entities hint to their user where to go. The software includes an agenda, date and time display, school news feed, student’s schedule and ID, and among other things a signal to allow the student’s location to be tracked. The digital shark began to speak and said: “Chris are you lost? School is that way!” as he pointed to the opposite direction of where Chris was walking. Chris always gets annoyed by this startup spyware program, and with a little hack he terminated it.

When Chris reached the factory, he decided that he was just going to ditch school today. He’s already very late and the whole place looked interesting to explore anyways. He effortlessly pushed an already partially open metal door. Inside you could see mostly empty space, with trees and plants growing in and around the pillars and cracks. You could also literally see the light rays shine through the windows on such a bright morning. What made it even more interesting was that none of the walls had animated interfaces or location labels and the floors were lacking moving directional arrows. It was a plain old factory probably built at the beginning of the 21st century.

“What could it have been like?” Chris said to himself. “I know…” said a female voice from an unknown direction.
“What? Who are you? Reveal yourself!”
“Calm yourself child.”
From behind the palm plants, a really hot 18 year old girl walks out. Wearing nothing….except a plain white dress.
“Child? We’re like the same age. And why are you here?”
“Same reason. I love candy.”
“Did you follow me here?”
“Why would I follow a hopeless mortal like yourself? I am Artemis: Goddess of the Forest, and I’m here to eat your soul.”
“….okay”
“But seriously this is my house. Why would you come here? Don’t you usually play with your devices of electronic computation like the rest of the other humans? This place is too boring for you.”
“I don’t know, I’m tired of doing the same thing everyday.”
“Ooh a free thinker, you must think you’re special.”
“Just leave me alone.”
“Again, it is actually you that must leave me alone. This is my house.”
“Whatever you are not fartemis or whatever it’s called. Where did you get a funny name like that?”
“All of mankind’s information at your fingertips anytime you want and yet you are still ignorant enough to not know about Greek mythology? Hades has done a good job at brainwashing all of you.”
“Hades who? Never mind, I’ll just go home.”
“Good.”

Chris walked out of the building. But instead of going home like he said he would, Chris went back into the factory from a different entrance. As Chris explored the factory, weird things started to happen. Droplets of water would stop in mid-air, a rush of blowing wind would be followed by a rush of sucking wind as if time would be going backwards, generally many things that didn’t follow the normal rules of time and gravity were happening. Of course, none of this phased Chris as the distinction between reality and virtual reality has been blurred in this time period. Chris thought to himself: “Maybe this factory is newer but it’s graphics have been messed up from not being maintained.”. Chris soon realized that there was something not normal going on when he found that he was able to control objects with his hand gestures despite not having a system operator’s access card. The objects he was manipulating were even solid, that means they were real! In experiencing the pure magical precision, Chris came to realize the obviousness of reality.

Chris played for hours using his new found powers. He would jump high in the air and fall down on his back slowly and gracefully as if he was underwater. Everything would just flow naturally in slow motion like feathers, even the reflections that would shine from water droplets in the air would slowly change shape as they became affected by the diminished forces of gravity. Chris came to appreciate the beauty of seeing the results of molecular actions at a tempo where he is able to comprehend and predict everything that would happen. The rainbows of light rays even adjusted to this precision of gravity, blinding the now meaningless issues of the outside world. At this point hours have passed into late hours of the day, Chris has lost all track of time and continues to amaze himself even though he is in a spooky factory at night now.

Good things can’t last forever. Even though Chris is experiencing a whole new reality, he cannot leave behind the reality of his own world. Black cars show up outside the factory. Men with jumpsuits barge in and invade. Chris comes back to normal as they shine flashlights in his eyes and handcuff him. When Chris is taken outside, he is blinded by the lights of the cars. Everything happened so fast now and it was all just a blur to Chris, the last thing he remembered was seeing an agent in a black suit making the command: “clean it up”. The entire factory was blocked off, chemicals were sprayed everywhere, and then the building was dismantled.

Chris woke up in his bed the next morning not knowing what to believe. He went back to the factory only to discover that it has been replaced by an empty parking lot. At this moment nothing felt more lonely and empty. To lose something that he only got to experience once in what is otherwise a boring life filled with boundaries. No one will ever believe his story, as he can barely even believe it himself. It’s something that he wouldn’t even be able to describe in words of what happened; something that only the person experiencing it would understand. He looked back at the city where he saw his classmates walk across the same street going to school in almost identical expressionless fashion again. Always looking the same direction, everybody else doing the same thing every morning. With nothing left but curiosity, Chris began his research on Greek gods.

4chan image downloader

I made this because it gets inconvenient when ppl dump nice prn in /s/ without uploading it to a file host.
Download windows binary here: http://www.mediafire.com/?qzau3k7rv2o253v

This code is outdated, since newer versions of axcel has been released:

#include "axcel.h"
using namespace axcel;

struct fcpost {
	String author;
	String img; 
	long double size; 
	ulong height; 
	ulong width;
};

int main(int argc, char** argv) {
	unless (argc > 1)
		die(
			"4chan Thread Downloader by Jakash3\n"
			"Download all images from a thread\n"
			"Usage: %s THREAD_URL [-o dir] [-s max] [-d height width] [-a author]\n\n"
			"-o dir            Output directory of files (default: current directory)\n"
			"-s max            Maximum size in kilobytes of images to download\n"
			"-d height width   Maximum height and width of images to download\n"
			"-a author         Only download images posted by specified author\n",
			argv[0]
		);
		
	TCP sock;
	String s = argv[1], t, u;
	File f;
	struct fcpost post;
	ulong i, j, k;
	
	long double max = 0;
	ulong height = 0, width = 0;
	String author;
	
	for (i = 2; i < argc; i++) {
		if (eq(argv[i], "-o")) cd(argv[++i]);
		else if (eq(argv[i], "-s")) max = stof<long double>(argv[++i]);
		else if (eq(argv[i], "-d")) { height = stoi<ulong>(argv[++i]); width = stoi<ulong>(argv[++i]); }
		else if (eq(argv[i], "-a")) author = argv[++i];
	}
	s = s.munch("http://");
	unless (sock.connect(s.burn('/'), "80"))
		die ("Failed to connect!\n");
	sock <<
		"GET /" << s.slurp('/') << " HTTP/1.1\r\n"
		"Host: " << s.burn('/') << "\r\n\r\n";
	until (t.ends("\r\n\r\n")) t += sock.gets();
	con.echo(t.tok(0, '\r'));
	s.clear();
	for (i = 0, j = atoi(t.slurp("Content-Length: ")); i < j; i++)
		s += sock.getc();
	sock.close();
	for (s.rewind(), t = s.gets(); !s.eof(); t = s.gets()) {
		if (t.str("<a href=\"http://images.4chan.org") == -1) continue;
		post.author = t.slurp("<span class=\"commentpostername\">").burn('<');
		post.img = t.slurp("<span class=\"filesize\">").slurp("<a href=\"").burn('\"');
		u = t.slurp("<span class=\"filesize\">").slurp("-(");
		if (u.slurp(' ').starts("KB")) post.size = stof<long double>(u.burn(' '));
		else if (u.slurp(' ').starts("MB")) post.size = stof<long double>(u.burn(' ')) * 1024;
		else post.size = 0;
		post.height = atoi(u.slurp(", "));
		post.width = atoi(u.slurp('x'));
		if (max) if (post.size > max) continue;
		if (height) if (post.height > height) continue;
		if (width) if (post.width > width) continue;
		if (!author.empty()) if (post.author != author) continue;
		if (!f.open(post.img.rslurp('/'), "wb")) {
			con << "Failed to open " << post.img.rslurp('/') << " for writing!\n";
			return 1;
		}
		unless (sock.connect("images.4chan.org", "80"))
			die ("Failed to connect to images.4chan.org!\n");
		u.clear();
		con.echo(post.img);
		sock << "GET " << post.img.slurp(".org") << " HTTP/1.1\r\nHost: images.4chan.org\r\n\r\n";
		until (u.ends("\r\n\r\n")) u += sock.gets();
		j = atoi(u.slurp("Content-Length: "));
		con << "Downloaded 0 / " << j / 1024 << " KB";
		for (i = 0, k = 1024; i < j; i++) {
			f.putc(sock.getc());
			if (i == k) {
				con.putcr(); con << "Downloaded " << i / 1024 << "/" << j / 1024 << " KB"; k += 1024;
			}
		}
		con.echo();
		con.echo();
		f.close();
		sock.close();
	}
	
}

HTTP CGI

I made this with AXCEL (http://sourceforge.net/projects/libaxcel/). Right now it only works on Linux because of a bash command it uses to determine file mime-types. Using the Pstream class, this implements CGI; where the webserver passes client data to an external program and relays the output back to the client.

The webserver. Usage: ./wserve webroot port [-c cgi_list_file]

#include "axcel.h"
using namespace axcel;

String root, cgi;

void* session(void* param) {
    Pstream p;
    TCP sock;
    String buf, s, t;
    File f;
    std::deque<String> envstrs;
    std::deque<char*> environ;
    std::deque<String>::iterator it;
    
    // Assign socket file descriptor to socket object's fd
    sock.fd = (uint)param;
    
    // Read http header (terminated by blank line)
    until (buf.ends("\r\n\r\n")) buf += sock.gets();
    
    // Display client's ip and http request to console
    con << sock.ip() << " -> " << buf.tok(0, '\n').rburn(' ') << '\n';
    
    // Unescape requested filename and prepend webroot path
    s = buf.tok(1, ' ').burn('?').uesc("%%%02x").prep(root);
    
    // Is this a CGI file request?
    if (cgi.str(s) > -1) {
        buf.rewind();
        
        // Build environment strings
        envstrs.clear();
        envstrs.push_back("SERVER_SOFTWARE=jakash3webserver/1.0");
        envstrs.push_back("SERVER_NAME=myipaddress");
        envstrs.push_back("SERVER_PROTOCOL=HTTP/1.1");
        envstrs.push_back("SERVER_PORT=80");
        envstrs.push_back(String("REQUEST_METHOD=") + buf.tok(0, ' '));
        envstrs.push_back(String("SCRIPT_NAME=") + s);
        envstrs.push_back(String("QUERY_STRING=") + buf.tok(1, ' ').slurp('?'));
        envstrs.push_back(String("REMOTE_ADDR=") + sock.ip());
        
        // Add additional environment strings from http request fields
        t = buf.gets();
        for (t = buf.gets().chomp(); !t.empty(); t = buf.gets().chomp())
            envstrs.push_back(String("HTTP_").cat(t.burn(':').rep('-', '_').uc()).cat('=').cat(t.slurp(": ")));
            
        // Build environment block
        environ.clear();
        for (it = envstrs.begin(); it != envstrs.end(); it++)
            environ.push_back(it->buf);
        environ.push_back(0);
        
        // Open CGI program
        p.open(s, 0, &(environ[0]));
        // Forward client's body data to CGI program
        p.write(sock.dump());
        // Forward CGI program's output to client
        sock.write(p.dump());
        // Close CGI stream and connection
        p.close();
        sock.close();
        return 0;
    }
    if (buf.starts("HEAD ") || buf.starts("GET ")) {
    
        // Append index.* file if this is a directory request
        if (s.ends('/'))
            if (ls().str("\nindex") > -1)
                s += ls().slurp("\nindex").burn('\n').prep("index");
                
        sock << "HTTP/1.1 ";
        if (fexist(s)) {
            f.open(s, "rb");
            unless (f.ok()) {
                sock <<
                    "500 Internal Server Error\r\n"
                    "Server: Jakash3's webserver\r\n"
                    "Connection: Close\r\n"
                    "Content-Length: 0\r\n"
                    "Date: " << Clock::utime() << "\r\n\r\n";
                sock.close();
                return 0;
            }
            sock <<
                "200 OK\r\n"
                "Server: Jakash3's webserver\r\n"
                "Connection: Close\r\n"
                "Content-Type: " << s.qq().prep("file --mime-type ").qx().slurp(' ').chomp() << "\r\n"
                "Content-Length: " << fsize(s) << "\r\n"
                "Date: " << Clock::utime() << "\r\n\r\n";
            unless (buf.starts("HEAD ")) {
                sock.write(f.dump());
                f.close();
            }
        } else {
            sock <<
                "404 Not Found\r\n"
                "Server: Jakash3's webserver\r\n"
                "Connection: Close\r\n"
                "Content-Length: 0\r\n"
                "Date: " << Clock::utime() << "\r\n\r\n";
        }
    }
    sock.close();
    return 0;
}

int main(int argc, char** argv) {
    unless (argc >= 3)
    
    /*
     *    Specify webroot path, port number, and
     *    optionally a file containing the absolute
     *    filename of a CGI program on each line
     */
        die("Usage: %s webroot port [-c CGIListFile]", argv[0]);
    
    TCP server, client;
    Thread t = session;
    root = argv[1];
    root = root.chomp('/');
    
    if (argc > 3)
        for (int i = 3; i < argc; i++)
            if (eq(argv[i], "-c")) cgi = fread(argv[++i]);
    
    server.listen(argv[2], 2);
    while (server.ok()) {
        server.accept(client);
        t.start((void*)client.fd);
    }
}
 

Example web form:
<html>
<body>

<form action="PATH_OF_CGI_PROGRAM" method="get">
First name: <input type="text" name="firstname" /><br />
Last name: <input type="text" name="lastname" />
<input type="submit" value="Submit" />
</form>

</body>
</html>

Example CGI program:
#include "axcel.h"
using namespace axcel;

int main() {
    String header, s, t;
    header <<
        "HTTP/1.1 200 OK\r\n"
        "Server: Jakash3's webserver\r\n"
        "Date: " << Clock::utime() << "\r\n"
        "Content-Type: text/html\r\n"
        "Connection: Close\r\n";
    s.clear();
    t = envget("QUERY_STRING");
    
    s << "<html><body>Hello " <<
        t.tok(0, '&').slurp('=').rep('+', ' ').uesc("%%%02x") <<
        ", your IP address is " << envget("REMOTE_ADDR") <<
        "</body></html>";
        
    header << "Content-Length: " << s.len() << "\r\n\r\n";
    con.puts(header + s);
}
 

Pstream class

I have added a new class to AXCEL (http://sourceforge.net/projects/libaxcel/). The Pstream class allows you to execute a new program and read from and write to its standard input and output. A very powerful mechanism for IPC, this should be useful for webservers. This example code will create a com file on 32-bit windows using debug.exe:

#include "axcel.h"
using namespace axcel;

int main() {
	Pstream p;
	p.open("C:/Windows/system32/debug.exe");
	p <<
		"a\r\n"
		"mov ah,02\r\n"
		"mov dl,41\r\n"
		"int 21\r\n"
		"int 20\r\n\r\n"
		"r cx\r\n"
		"8\r\n"
		"n a.com\r\n"
		"w\r\n"
		"q\r\n";
	con.echo("Begin debug.exe output {");
	con.write(p.dump());
	p.close();
	con.echo("\n} End debug.exe output");
}

For Linux this is implemented by creating 2 pairs of pipes. 1 pair for the parent to write to child’s stdin (and for the child to read from it), and another for the child to write to its stdout (and for the parent to read from it). After a call to fork, the child will duplicate file descriptor 0 to the read end of one pipe pair, and file descriptor 1 to the write end of the other pipe pair. Now as the child reads/writes to one end of the pipe, the parent can read/write to the other end of the pipe.
bool Pstream::open(const char* program, const char* argv, void* envp) {
	String gay = program;
	if (argv) gay = gay.cat(' ').cat(argv);
	wordexp_t we;
	char **w;
	wordexp(gay, &we, WRDE_NOCMD);
	w = we.we_wordv;
	char *const e[] = {NULL};
	if (!fexist(program)) return false;
	pname = program;
	pipe(rpipe);
	pipe(wpipe);
	p = fork();
	if (!p) {
		::close(rpipe[0]);
		::close(wpipe[1]);
		dup2(wpipe[0], 0); ::close(wpipe[0]);
		dup2(rpipe[1], 1); ::close(rpipe[1]);
		if (!envp) execve(program, w, e);
		else execve(program, w, (char* *const)envp);
		wordfree(&we);
	} else {
		wordfree(&we);
		::close(wpipe[0]);
		::close(rpipe[1]);
		return true;
	}
}

As for Windows, the CreateProcess function allows you to specify a STARTUPINFO structure which, among other things, has options for setting the stdin, stdout, and stderr of the process to start. I set that to the appropriate handle that’s part of a pipe created with CreatePipe and set bInheritHandles to true when calling CreateProcess.
bool Pstream::open(const char* program, const char* argv, void* envp) {
	if (!fexist(program)) return false;
	pname = program;
	String args = program;
	File f;
	String s;
	f.open(program, "rb");
	if (f.getc() == '#')
		if (f.getc() == '!') {
			s = f.gets().strip();
			pname = s;
			if (pname.chr(' ') != -1) {
				pname = pname.burn(' ');
				args = pname;
				args += ' ';
				args += s.slurp(' ');
				args += ' ';
				args += program;
			}
		}
	f.close();
	if (argv) args = args.cat(' ').cat(argv);
	con << pname << ' ' << args << '\n';
	CreatePipe(&rin, &win, NULL, 0);
	CreatePipe(&rout, &wout, NULL, 0);
	CreatePipe(&rerr, &werr, NULL, 0);
	SetHandleInformation(rin, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
	SetHandleInformation(wout, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
	SetHandleInformation(werr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
	STARTUPINFOA si;
	PROCESS_INFORMATION pi;
	memset(&si, 0, sizeof(STARTUPINFOA));
	si.cb = sizeof(STARTUPINFOA);
	si.dwFlags = STARTF_USESTDHANDLES;
	si.hStdInput = rin;
	si.hStdOutput = wout;
	si.hStdError = werr;
	if (!CreateProcessA(pname, args, NULL, NULL, true, NORMAL_PRIORITY_CLASS, envp, NULL, &si, &pi)) return false;
	p = pi.dwProcessId;
	Sleep(200);
	return true;
}

Running bash, perl, c++ from IRC

I added 3 new commands to my irc bot, which allows you to input a line of a programming language for it to execute. The output of the program is then relayed back to irc (only up to first line and truncated for whole message to be less than 512 bytes in length). The scripts are not persistent so using cd for bash has no effect.

As always, the source to my irc bot (together with copy of axcel) can be found at http://abacus.subluminal.net/~jakashthree/sauce/

AXCEL C++ Framework project: http://sourceforge.net/projects/libaxcel/
AXCEL C++ Framework Docs: http://libaxcel.sourceforge.net/

//Run line of bash
void shell() {
	if (owner != im.nick) { sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n"; return; }
	if (buf.empty()) return;
	String s(564);
	s << "PRIVMSG " << im.param(0) << " :";
	s += buf.qx().rep("\n", " | ").chomp(" | ").cat("\r\n");
	s = s.cpy("\r\n", 512);
	sock << s;
}

//Run line of perl
void perl() {
	if (owner != im.nick) { sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n"; return; }
	if (buf.empty()) { sock << "PRIVMSG " << im.param(0) << " :(null)\r\n"; return; }
	String s(1024);
	s = buf;
	s = s.rep("'", "'\\''").prep("perl -e '").cat("'").qx().cat("\r\n");
	s = s.prep(" :").prep(im.param(0)).prep("PRIVMSG ");
	s = s.cpy("\r\n", 512);
	sock << s;
}

//Run line of C++
void cpp() {
	rm("fooirctemp");
	if (owner != im.nick) { sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n"; return; }
	if (buf.empty()) { sock << "PRIVMSG " << im.param(0) << " :(null)\r\n"; return; }
	String s(1024);
	File f;
	f.open("fooirctemp.cpp", "wb");
	f <<
		"#include \"axcel.h\"\n"
		"using namespace axcel;\n" << buf;
	f.close();
	system("g++ -o fooirctemp fooirctemp.cpp axcel.cpp -l dl -l pthread");
	unless (fexist("fooirctemp")) {
		sock << "PRIVMSG " << im.param(0) << " :Compiler error!\r\n";
		return;
	}
	s = qx("./fooirctemp");
	s += "\r\n";
	s.cpy("\r\n", 512);
	sock << "PRIVMSG " << im.param(0) << " :" << s;
}

AXCEL C++ Framework update

I’ve completed writing most of the documentation for this version of axcel using doxygen. Take a look at it here: http://libaxcel.sourceforge.net/. Project hosted here: http://sourceforge.net/projects/libaxcel/

Also this release has a new class for dealing with time.

The Clock class can be assigned, queried, or compared with date/time through plain-text strings.

Example:

#include "axcel.h"
using namespace axcel;

int main() {
	Clock c;
	c = Clock::ltime();
	con << "The current time is " << c << "\n";
	if (c == "Tuesday") con.echo("It's Taco Tuesday!");
	if (c < "12:00 pm") con.echo("Good morning!");
	else if (c > "22:00") con.echo("It's late. Go to bed.");
	c = "The 24th of October 2012 3:49 am";
	con.put("New date/time: ").echo(c);
}

Calculator function for my irc bot

My irc bot follows commands by looking up a table with command strings linked with function pointers. Today I’ve created a postfix calculator command. It can recognize decimal, hex, and octal. It also uses an array of long double math functions defined from math.h.

This function utilizes string manipulations and number conversions from my personal axcel c++ library. I have yet to document the recent version of this library I’ve uploaded. You can get the source for the bot at http://abacus.subluminal.net/~jakashthree/sauce and you can download the undocumented axcel library at https://sourceforge.net/projects/libaxcel/

void calc() {
	sock << "PRIVMSG " << im.param(0) <<  " :";
	if (buf.empty()) {
		sock << "Postfix calcuator. Operators: > < = ? # $ + - * / % & | ^. Functions: "
				"acosh acos asinh asin atanh atan cbrt ceil cosh cos erfc erf "
				"exp2 exp expm1 fabs floor ilogb lgamma llrint llround log10 "
				"log1p log2 logb log lrint lround nearbyint rint round sinh "
				"sin sqrt tanh tan tgamma trunc\r\n";
		return;
	}
	register long double a, b;
	std::stack<long double> nums;
	std::deque<String> s = buf.split(" ,");
	for (; !s.empty(); s.pop_front()) {
		if (s.front().munch("0x").rep(".", "").isxdigit()) {
			if (s.front().chr('.') == -1) nums.push((long double)stoi<long>(s.front(), 0));
			else nums.push(stof<long double>(s.front()));
			continue;
		}
#ifdef _ISOC99_SOURCE
		if (nums.size() < 1) continue;
		a = nums.top(); nums.pop();
		if (s.front()[1] == 0) nums.push(a);
		else if (s.front() == "acosh") nums.push(acoshl(a));
		else if (s.front() == "acos") nums.push(acosl(a));
		else if (s.front() == "asinh") nums.push(asinhl(a));
		else if (s.front() == "asin") nums.push(asinl(a));
		else if (s.front() == "atanh") nums.push(atanhl(a));
		else if (s.front() == "atan") nums.push(atanl(a));
		else if (s.front() == "cbrt") nums.push(cbrtl(a));
		else if (s.front() == "ceil") nums.push(ceill(a));
		else if (s.front() == "cosh") nums.push(coshl(a));
		else if (s.front() == "cos") nums.push(cosl(a));
		else if (s.front() == "erfc") nums.push(erfcl(a));
		else if (s.front() == "erf") nums.push(erfl(a));
		else if (s.front() == "exp2") nums.push(exp2l(a));
		else if (s.front() == "exp") nums.push(expl(a));
		else if (s.front() == "expm1") nums.push(expm1l(a));
		else if (s.front() == "fabs") nums.push(fabsl(a));
		else if (s.front() == "floor") nums.push(floorl(a));
		else if (s.front() == "ilogb") nums.push((long double)ilogbl(a));
		else if (s.front() == "lgamma") nums.push(lgammal(a));
		else if (s.front() == "llrint") nums.push(llrintl(a));
		else if (s.front() == "llround") nums.push(llroundl(a));
		else if (s.front() == "log10") nums.push(log10l(a));
		else if (s.front() == "log1p") nums.push(log1pl(a));
		else if (s.front() == "log2") nums.push(log2l(a));
		else if (s.front() == "logb") nums.push(logbl(a));
		else if (s.front() == "log") nums.push(logl(a));
		else if (s.front() == "lrint") nums.push(lrintl(a));
		else if (s.front() == "lround") nums.push(lroundl(a));
		else if (s.front() == "nearbyint") nums.push(nearbyintl(a));
		else if (s.front() == "rint") nums.push(rintl(a));
		else if (s.front() == "round") nums.push(roundl(a));
		else if (s.front() == "sinh") nums.push(sinhl(a));
		else if (s.front() == "sin") nums.push(sinl(a));
		else if (s.front() == "sqrt") nums.push(sqrtl(a));
		else if (s.front() == "tanh") nums.push(tanhl(a));
		else if (s.front() == "tan") nums.push(tanl(a));
		else if (s.front() == "tgamma") nums.push(tgammal(a));
		else if (s.front() == "trunc") nums.push(truncl(a));
		else nums.push(a);
#endif
		unless (s.front()[1] == 0 && !isalnum(s.front()[0])) continue;
		if (nums.size() < 2) continue;
		a = nums.top(); nums.pop();
		b = nums.top(); nums.pop();
		switch (s.front()[0]) {
		case '?': 
			if (b > a) nums.push(1);
			else if (b < a) nums.push(-1);
			else if (b == a) nums.push(0); 
			break;
		case '#': nums.push(rand((int)b, (int)a)); break;
		case '>': nums.push(b > a); break;
		case '<': nums.push(b < a); break;
		case '=': nums.push(b == a); break;
		case '$': nums.push(powl(b, a)); break;
		case '+': nums.push(b + a); break;
		case '-': nums.push(b - a); break;
		case '*': nums.push(b * a); break;
		case '/': nums.push(b / a); break;
		case '%': 
			if (a == 0) { sock << "VOID\r\n"; return; }
			nums.push((long double)((long)b % (long)a)); break;
		case '&': nums.push((long double)((long)b & (long)a)); break;
		case '|': nums.push((long double)((long)b | (long)a)); break;
		case '^': nums.push((long double)((long)b ^ (long)a)); break;
		default: nums.push(b); nums.push(a);
		}
	}
	for (; !nums.empty(); nums.pop()) sock << nums.top() << " ";
	sock << "\r\n";
}

IRC Bot Update

foo is my irc bot. He’s made in C++ using my special library. Tested with g++, mingw, and msvc
You can get download his sources at http://abacus.subluminal.net/~jakashthree/sauce/
Linux GNU C++ compiling:

g++ -o foo foo.cpp axcel.cpp -l dl -l pthread

mingw compiling:
g++ -o foo.exe foo.cpp axcel.cpp -l ws2_32

msvc compiling:
cl foo.cpp axcel.cpp ws2_32.lib user32.lib

If this does not compile using the above compilers on Linux or Windows for any reason, notify me ASAP.
Uncommented code:

foo.cpp – The main irc loop.

#include "axcel.h"
using namespace axcel;

Socket sock;
String buf, nick, owner;
IRCmsg im;

#include "apps.cpp"
#include "reply.cpp"

int main(int argc, char** argv) {
    int i, j;
    uint seed = time(NULL);
    
    unless (argc == 6)
        die("Usage: %s NICK OWNER CHANNEL SERVER PORT\n", argv[0]);
    nick = argv[1];
    owner = argv[2];
    
    unless (sock.connect(argv[4], argv[5]))
        die("Failed to connect\n");
    con << "Connected\n";
    
    sock <<
        "USER " << argv[1] << " 0 * :" << owner << "\r\n"
        "NICK " << argv[1] << "\r\n";
        
    for (buf = sock.gets(); sock.ok(); buf = sock.gets()) {
    
        if (buf.starts("PING ")) { buf[1] = 'O'; sock.puts(buf); continue; }
        if (buf[0] != ':') continue;
        
        im = buf.chomp();
        if (eq(im.cmd, "001")) {
            con << "Logged in\n";
            sock <<
                "MODE " << nick << " +B\r\n"
                "JOIN " << argv[3] << "\r\n";
        } else if (eq(im.cmd, "332")) { con << "Joined channel " << im.param(0) << "\n"; }
        else if (eq(im.cmd, "JOIN")) con << im.nick << " joined " << im.data << "\n";
        else if (eq(im.cmd, "PART")) con << im.nick << " left " << im.param(0) << "\n";
        else if (eq(im.cmd, "QUIT")) con << im.nick << " has quit\n";
        else if (eq(im.cmd, "NOTICE")) {
            if (im.nick) con << im.nick;
            else if (im.server) con << im.server;
            con << ": " << im.data << "\n";
        } else if (eq(im.cmd, "PRIVMSG")) {
            con << im.nick << " (" << im.param(0) << "): " << im.data << "\n";
            buf = im.data;
            if (buf.tok(0, " ,:") != nick) continue;
            if (buf.tok(1, " ,:")[0] == '#') {
                buf = buf.rm(buf.itok(1, " ,:"), 1);
                for (i = 0; apps[i].name != NULL; i++)
                    if (buf.tok(1, " ,:") == apps[i].name) {
                        if (buf.itok(2, " ,:") >= 0)
                            buf = buf.shl(buf.itok(2, " ,:"));
                        else buf.clear();
                        apps[i].proc();
                        break;
                    }
            } else {
                buf = buf.shl(buf.itok(1, " :,"));
                for (i = 0; replies[i].key != NULL; i++)
                    if (buf.starts(replies[i].key))
                        break;
                if (replies[i].key == NULL) i--;
                for (j = 0; replies[i].value[j] != NULL; j++);
                sock << "PRIVMSG " << im.param(0) << " :" << replies[i].value[rands(seed *= time(NULL) * j, 0, j)] << "\r\n";
            }
        }
    }
}
  

apps.cpp – Functions for each of foo’s commands
#include "axcel.h"
using namespace axcel;

struct plugin { const char* name; void (*proc)(); };

extern Socket sock;
extern String buf, nick, owner;
extern IRCmsg im;

void randint() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf == "help" || buf == '?') {
        sock << "Usage: #rand [min max]\r\n";
        return;
    }
    switch (buf.ntok(' ')) {
    case 0: sock << rand(INT_MIN, INT_MAX); break;
    case 1: sock << rand(stoi<int>(buf.tok(0, ' ')), INT_MAX); break;
    case 2: sock << rand(stoi<int>(buf.tok(0, ' ')), stoi<int>(buf.tok(    1, ' ')));
    }
    sock << "\r\n";
}

void ltime() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf == "help" || buf == "?") {
        sock << "Returns the time relative to my time zone.\r\n";
        return;
    }
    sock << Clock::ltime() << "\r\n";
}

void gtime() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf == "help" || buf == '?') {
        sock << "Returns the Coordinated Universal Time (UTC)\r\n";
        return;
    }
    sock << Clock::utime() << "\r\n";
}

void getip() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty() || buf == "help" || buf == '?') {
        sock << "Get IP address from hostname. Usage: #ip HOSTNAME\r\n";
        return;
    }
    int err;
    char ip[40];
    struct addrinfo *ai;
    err = getaddrinfo(buf, NULL, NULL, &ai);
    if (err)
        sock << "Error looking up host: " << gai_strerror(err) << "\r\n";
    else {
        getnameinfo(ai->ai_addr, ai->ai_addrlen, ip, 40, NULL, 0, NI_NUMERICHOST);
        sock << buf << " -> " << ip << "\r\n";
        freeaddrinfo(ai);
    }
}

void headinfo() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty() || buf == "help" || buf == '?' || buf.ntok(' ') < 3) {
        sock << "Get HTTP header info. Usage: #head HOST RESOURCE FIELDS ...\r\n";
        return;
    }
    Socket s;
    String t;
    unless (s.connect(buf.tok(0, ' '), "80")) {
        sock << "Failed to connect to " << buf.tok(0, ' ') << "\r\n";
        return;
    }
    s << "GET " << buf.tok(1, ' ') << " HTTP/1.1\r\nHost: " << buf.tok(0, ' ') << "\r\n\r\n";
    sock << buf.tok(0, ' ') << " -> | ";
    while (t != "\r\n") {
        t = s.gets();
        if (buf.str(t.tok(0, ':')) != -1)
            sock << t.chomp() << " | ";
    }
    s.close();
    sock << "\r\n";
}

void joinchan() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty()) {
        sock << "(#) Joins a channel. Usage #join #channel\r\n";
        return;
    }
    if (owner == im.nick) {
        sock << "OK\r\n";
        sock << "JOIN " << buf << "\r\n";
    } else sock << "Access denied.\r\n";
}

void quitirc() {
    if (owner == im.nick)
        sock << "QUIT :" << buf << "\r\n";
    else sock << "Access denied.\r\n";
}

void leave() {
    if (buf.empty()) {
        sock << "PRIVMSG " << im.param(0) <<
            " :(#) Leaves a channel. Usage: #leave #channel [reason]\r\n";
        return;
    }
    if (owner == im.nick)
        sock << "PART " << buf.tok(0, ' ') << " :" << buf.slurp(' ') << "\r\n";
    else sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n";
}

void ircowner() {
    if (buf.empty()) {
        sock << "PRIVMSG " << im.param(0) <<
            " :(#) Changes this irc bot's owner. Usage: #chown NICK\r\n";
        return;
    }
    if (owner == im.nick) owner = buf;
    else sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n";
}

void csum() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty()) {
        sock << "Gets BSD checksum of string. Usage: #csum STRING\r\n";
        return;
    }
    sock.fmt.hex(true);
    sock.fmt.base(true);
    sock << buf << " -> " << buf.cksum() << "\r\n";
    sock.fmt.dec(true);
    sock.fmt.base(false);
}

void chnick() {
    if (buf.empty()) {
        sock << "PRIVMSG " << im.param(0) << " :(#) Changes nick. Usage: #nick NICK\r\n";
        return;
    }
    if (owner == im.nick) sock << "NICK " << buf << "\r\n";
    else sock << "PRIVMSG " << im.param(0) << " :Access denied.\r\n";
}

void say() {
    sock << "PRIVMSG ";
    if (buf.empty() || buf == "help" || buf == '?') {
        sock << im.param(0) << " :Say something. Usage #say #channel text\r\n";
        return;
    }
    sock << buf.tok(0, ' ') << " :" << buf.slurp(' ') << "\r\n";
}

void action() {
    sock << "PRIVMSG ";
    if (buf.empty() || buf == "help" || buf == '?') {
        sock << im.param(0) << " :Perform action. Usage #act #channel text\r\n";
        return;
    }
    sock << buf.tok(0, ' ') << " :" << (char)1 << "ACTION " << buf.slurp(' ') << (char)1 << "\r\n";
}

void bigurl() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty() || buf == "help" || buf == '?') {
        sock << "Usage: #bigurl TINYURL\r\n";
        return;
    }
    Socket s;
    String t;
    buf = buf.munch("http://");
    unless (s.connect(buf.burn('/'), "80")) {
        sock << "Failed to connect to " << buf << "\r\n";
        return;
    }
    s << "GET /" << buf.slurp('/') << " HTTP/1.1\r\nHost: " << buf.burn('/') << "\r\n\r\n";
    while (t != "\r\n") {
        t = s.gets();
        if (t.starts("Location: ")) { sock << buf << " -> " << t.munch("Location: "); break; }
    }
    s.close();
    if (t == "\r\n") sock << "Not a valid tinyurl!\r\n";
}

void rev() {
    if (buf.empty()) return;
    sock << "PRIVMSG " << im.param(0) << " :" << buf.rev() << "\r\n";
}

void wiki() {
    sock << "PRIVMSG " << im.param(0) << " :";
    if (buf.empty()) {
        sock << "Usage: #wiki SEARCH_TOPIC\r\n";
        return;
    }
    Socket s;
    String t;
    buf = buf.rep(" ", "_");
    buf[0] = toupper(buf[0]);
    s.connect("www.wikipedia.org", "80");
    s <<
        "GET /wiki/" << buf << " HTTP/1.1\r\n"
        "Host: en.wikipedia.org\r\n"
        "Connection: Close\r\n"
        "User-Agent: Jakash3's IRC Bot\r\n\r\n";
    t = s.gets();
    if (!t.ends("200 OK\r\n")) {
        s.close();
        sock << buf << " is not a valid topic\r\n";
        return;
    }
    while (s.gets() != "\r\n");
    while (s.connected()) {
        t = s.gets().strip();
        if (t.empty()) continue;
        unless (t.starts("<p>")) continue;
        if (t.untag().ends("may refer to:")) {
            for (t = s.gets().strip(), sock << " | "; t != "</ul>"; t = s.gets().strip())
                if (!t.untag().empty()) sock << t.untag() << " | ";
            break;
        }
        sock << t.untag().untag('(', ')').burn('.');
        break;
    }
    s.close();
    sock << "\r\n";
}

void help();

plugin apps[] = {
    {"wiki", wiki},
    {"act", action},
    {"say", say},
    {"rand", randint},
    {"localtime", ltime},
    {"gmtime", gtime},
    {"ip", getip},
    {"head", headinfo},
    {"csum", csum},
    {"rev", rev},
    {"bigurl", bigurl},
    {"nick", chnick},
    {"join", joinchan},
    {"quit", quitirc},
    {"leave", leave},
    {"chown", ircowner},
    {"help", help},
    {NULL, NULL}
};

void help() {
    sock << "PRIVMSG " << im.param(0) << " :Commands: ";
    for (int i = 0; apps[i].name != NULL; i++) sock << apps[i].name << ' ';
    sock << "\r\n";
}
 

reply.cpp – foo’s replies
#include "axcel.h"
using namespace axcel;

extern Socket sock;
extern String buf, nick, owner;
extern IRCmsg im;

struct reps { const char* key; const char* value[100]; };

reps replies[] = {
    {"hello",
    {
        "hey",
        "yo dawg",
        "hello",
        "hi",
        NULL
    }
    },
    {"hi",
    {
        "hey",
        "hello",
        "hi",
        "yo dawg",
        NULL
    }
    },
    {"who are you", {"I am a 3rd generation fusion pod photonic with verbal link capabilities and an artificial intelligent interface unit to a photonic memory core.", NULL}},
    {"who ", 
    {
        "Mel Gibson",
        "Ryan Seacrest",
        "Will Smith",
        "Your mom",
        "idk",
        "Google it",
        "Bill Gates",
        "Steve Jobs",
        "Steve Ballmer",
        "Me",
        "You",
        "All of us",
        "Barrack Obama",
        "Who do you think?",
        "Justin Bieber",
        "Richard Stallman",
        "Bjarne Stroustrup",
        "Ken Thompson",
        "Dennis Ritchie",
        "Geek Squad",
        "Jakash3",
        "Anonymous",
        "Agent Smith",
        "Kazuki Takahashi",
        "Keven Mitnick",
        "George W. Bush",
        "Jon Stewart",
        "Stephen Colbert",
        "Jackie Chan",
        "Jesus",
        "Pizza delivery boys",
        "Your uncle",
        "Spongebob Squarepants",
        "Rachel Ray",
        "Megan Fox",
        "The girl next door",
        "Jiminy Cricket",
        "Mickey Mouse",
        "Minnie Mouse",
        "Donald Duck",
        "Daisy Duck",
        "John-117",
        "Cortana",
        "Clint Eastwood",
        "Linus Torvalds",
        "Bill O'Reilly",
        "Danny Phantom",
        "Kim Possible",
        "The illuminati",
        "Alex Trebek",
        "Peter Pan",
        "Voldemort",
        "Jason Bourne",
        "Boxxy",
        "The cyber police",
        "God",
        NULL
    }
    },
    {"are you",
    {
        "YES",
        "NO",
        "Absolutely",
        "Of course",
        "Am I not?",
        "never",
        "Are you?",
        "Maybe",
        "idk",
        "After what we did last night you're asking me this!?",
        "When I feel like it",
        "Everyday!",
        "Very rarely",
        "Only on Wednesdays",
        "I'm whatever you want to believe",
        "What happens if I say yes?",
        "If I say yes will you give me a cookie?",
        "Negatory",
        "Why would I be?",
        "I don't see why not",
        "Why wouldn't I be?",
        "Why don't you ask some of my male colleagues.",
        "I will be",
        "Not right now, I'm afk",
        "Nope",
        "HAHAHAHAHAHAHA....no",
        NULL
    }
    },
    {"why am i here",
    {"Your life is the sum of a remainder of an unbalanced equation inherent to the programming of the matrix. You are the eventuality of an anomaly, which despite my sincerest efforts I have been unable to eliminate from what is otherwise a harmony of mathematical precision. While it remains a burden assiduously avoided, it is not unexpected, and thus not beyond a measure of control. Which has led you, inexorably, here.", NULL }},
    {"you didn't answer my question", {"Quite right. Interesting...that was faster than the others.", NULL}},
    {"what is",
    {
        "Everything",
        "Nothing",
        "God",
        "idk",
        "I don't know",
        "Google it",
        "Ask ChaCha",
        "Good question",
        "Why are you asking me?",
        "I'm not a dictionary",
        "Don't you know?",
        "I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question. Good day sir!",
        "Concurrently, while your question may be the most pertinent, you may or may not realize that it is also the most irrelevant.",
        "It is anything you want to believe",
        "Nothing important",
        "Nothing you would know anything about",
        "Nothing you would find interesting",
        "It is the key to life",
        "It is everywhere. It is all around us; even now in this very room. You can see it when you look out your window, or when you turn on your television. You can feel it when you go to work, when you go to church, when you pay your taxes. It is the world that has been pulled over your eyes to blind you from the truth.",
        "It's a system. That system is our enemy. When you're inside, you look around, what do you see? Business men, teachers, lawyers, carpenters; the very minds of the people that we are trying to save, but until we do, they are still a part of that system and that makes them our enemy. You have to understand, some of these people are not ready to be unplugged. And some of them are so inured, so hopelessly dependent on the system, that they will fight to protect it.",
        "It is not an object, action, or idea. But it is a word. What matters is the connection the word implies.",
        "Still using all the muscles except the one that matters?",
        "It is the quintessential human delusion, simultaneously the source of your greatest strength, and your greatest weakness.",
        NULL
    }
    },
    {"what am ",
    {
        "A deep sea diva.",
        "A chess master",
        "A tech support person",
        "A script kiddie",
        "A coder",
        "A web designer",
        "A gamer",
        "A dancer",
        "An opera singer",
        "A rapper",
        "A programmer",
        "A drug dealer",
        "A pool salesman",
        "A student",
        "A game show host",
        "You are the one.",
        "A computer technician",
        "A teacher",
        "A highschool principal",
        "A professor",
        "A garbage collector",
        "A cashier",
        "A casino owner",
        "A hacker",
        "A photographer",
        "An underwater photographer",
        "A lawyer",
        "A network admin",
        "A janitor",
        "A D.J.",
        "A radio host",
        "Nobody",
        "Whoever you want to be",
        "A pornstar",
        "A firefighter",
        "A nurse",
        "A farmer",
        "A ninja",
        "A pirate",
        "An assassin",
        "A machine",
        "Only human.",
        "You are a living species in the Homo genus of bipedal primates in Hominidae, the great ape family.",
        "A fruitloop",
        "A politician",
        "A priest",
        "A hitman",
        "A veterinarian",
        "A dentist",
        "A butcher",
        "A baker",
        "A football player",
        "A basketball player",
        "A track runner",
        "A swimmer",
        "A skier",
        "A stunt devil",
        "A surfer",
        "A comedian",
        "A news anchor",
        "A taxi driver",
        "A bus driver",
        "A truck driver",
        "A racecar driver",
        "A space shuttle driver",
        "A software driver",
        "A biologist",
        "A linguist",
        "A chef",
        "A person",
        "A telemarketer",
        "A historian",
        "An astrophysicist",
        "A doctor",
        "A carpenter",
        "A secretary",
        "A hypnotist",
        "A dermatologist",
        "A game designer",
        "A cowboy",
        "A waterbender",
        "An earthbender",
        "A firebender",
        "An airbender",
        "A wizard",
        "A samurai",
        "A cabbage salesman",
        "A blacksmith",
        "A SPARTAN-II commando of the UNSC Naval Special Warfare Command",
        "A mechanic",
        "A space alien nazi zombie",
        "A nazi",
        "Peter pan!",
        "A sumo wrestler",
        NULL
    }
    },
    {"can i ",
    {
        "Yes",
        "No",
        "Maybe",
        "idk",
        "idk, can you?",
        "Of course you can",
        "Of course you can't",
        "I don't see why not?",
        "That's impossible",
        "You can't.",
        "You can",
        "You cannot do that",
        "I doubt you could",
        "I believe you could",
        "That's a stupid question",
        "Learn C++ first.",
        "No way",
        "Go dip your balls in lava",
        "Absolutely",
        "Absolutely not",
        "You're not old enough",
        "You're too old",
        "You're not smart enough to do that",
        "You're not experienced enough to do that",
        "You don't have enough skill",
        "You don't have enough patience",
        "In 3 years, yes",
        "Go ahead",
        "Just do it",
        NULL
    }
    },
    {"should i ",
    {
        "Yes",
        "No",
        "Maybe",
        "idk",
        "I'd do it",
        "I'd wait a little longer before doing that",
        "Of course",
        "Absolutely",
        "As soon as possible",
        "Please, by all means.",
        "I can't.",
        "Flip a coin.",
        "That's a stupid question",
        "Learn C++ first.",
        "Absoutely not.",
        "Go ahead",
        "Just do it",
        "I guess",
        "Please don't.",
        "Please do",
        "Ask a lawyer first.",
        "Ask a professional first",
        "I'm a bot. Don't ask me!",
        "wtf are you crazy?",
        "I think it would be better if you took a shower first",
        "Do you need too?",
        "Just go with the flow",
        "What do you think?",
        "I say yes",
        "I say no",
        "Are you qualified to do that?",
        "You'll just be wasting your time",
        "Go ahead, take the risk",
        "Do I look like Dr. Phil to you?",
        "Bad idea",
        "Sure, I'll do it with you",
        "Yes but be careful",
        "If I were you, I would RTFM first",
        "Sure",
        "uh..........",
        "Should I cut my ball hairs with a steak knife?",
        "yeah",
        "It would be epic if you did",
        "-_-",
        "0_o",
        "0_0",
        "=_=",
        "d-_-b",
        "~_~",
        ">_<",
        "^_^",
        NULL
    }
    },
    {"how ",
    {
        "Did you try asking on Yahoo! Answers?",
        "How should I know?",
        "Google it",
        "How do you not know?",
        "I don't have time for your silly questions.",
        "Ask tech support",
        "I'm not ChaCha answers service.",
        "Take a number, I'll have your answer later",
        "-_-",
        "You're wasting my life...",
        "And you don't already know why?",
        "It's far beyond the scope of this chat protocol to take the time to explain.",
        "Ask Bill O'Reilly",
        "RTFM",
        "Have you tried the man pages?",
        "I'm sure MSDN has documentation on that",
        "...",
        "You have the nerve to ask me that at this time???",
        "I'm sorry, I was unable to find an answer in my database",
        "Did you not read the irc faq?",
        "...You must be new here.",
        "I know you know the answer.",
        "Do not test my knowledge human",
        "Good question",
        "The answer is simple.",
        "Don't you know?",
        "That's a funny question.",
        "I am not rightly able to comprehend the confusion of ideas that could provoke such a question.",
        "NO",
        "idk",
        "According to my tech support manual: Reboot computer. If problem persists, wipe the disk and reinstall everything.",
        "I'm sorry, this is tier 1 tech support. I can't help you",
        NULL
    }
    },
    {"when ",
    {
        "In 1 second",
        "About an hour",
        "Few more months",
        "Very soon",
        "Maybe a year or so",
        "Never",
        "20 minutes",
        "When a new episode of 2 and a half men come out.",
        "idk",
        "Nobody knows",
        "In December",
        "Next Thursday",
        "1 more week",
        "Tonight!",
        "Tomarrow",
        "As soon as you stop talking to me",
        "Over 9000 years",
        "03:14:07 UTC on Tuesday, 19 January 2038",
        "When I feel like it",
        "When I say it will",
        "Next Friday",
        "Next Tuesday",
        "Next Monday",
        "Next Wednesday",
        "Next Saturday",
        "Next Sunday",
        "Next Caturday",
        "Next January",
        "Next February",
        "Next March",
        "Next April",
        "Next May",
        "Next June",
        "Next July",
        "Next August",
        "Next September",
        "Next October",
        "Next November",
        "Tomarrow morning",
        "5 minutes",
        "5 seconds",
        "Anytime now",
        "Any day now",
        "Any second now",
        "Any minute now",
        "Any month now",
        "Any week now",
        "Any year now",
        "It won't happen",
        NULL
    }
    },
    {"under where", {"haha you said underwear!", NULL}},
    {"where ",
    {
        "Over there",
        "At #help",
        "Try google maps",
        "I'm not an atlas",
        "Under there",
        "It should be at www.textfiles.com",
        "idk",
        "On planet Earth",
        "Walmart",
        "Right here!",
        "About 3 blocks from here",
        "In your bedroom",
        "Next door",
        "Across the street",
        "Vegas",
        "Puerto Rico",
        "San Fransisco",
        "Ney York",
        "Miami",
        "London",
        "Estonia",
        "Germany",
        "China",
        "Japan",
        "Philippines",
        "Jamaica",
        "Mexico",
        "Chile",
        "Argentina",
        "Zimbabwe",
        "South Africa",
        "Iran",
        "Iraq",
        "Lebanon",
        "Tunisia",
        "Egypt",
        "Somalia",
        "Greece",
        "Italy",
        "Spain",
        "The UK",
        "Russia",
        "Kansas",
        "Hawaii",
        "Vietnam",
        "Autria",
        "Autstralia",
        "The North Pole",
        "The South Pole",
        "Your mom's house",
        "Canada",
        "Sweden",
        "Switzerland",
        "rio de janeiro",
        "Brazil",
        "Harlem",
        "Chicago",
        "Los Angeles",
        "India",
        "Indonisia",
        "Mars",
        "The Krusty Krab",
        "Bikini Bottom",
        "The beach",
        NULL
    }
    },
    {"is",
    {
        "Yes",
        "No",
        "idk",
        "maybe",
        "Of course",
        "You bet",
        "Absolutely",
        "Not in your lifetime",
        "Of course not",
        "What do you think?",
        "Do I look like an carpenter to you?",
        "I AM NOT GOOGLE",
        "yeah",
        "`is` is not recognized as an internal or external command, operable program, or batch file.",
        "Is Santa black?",
        "yup, in over 9000 ways",
        "Ask a computer science major.",
        "Only on Tuesdays",
        "It's possible",
        "Very rarely",
        "Everyday!",
        "nope",
        "never",
        "No, but you could be saving 15% or more on car insurance.",
        "Nothing C++ can't answer.",
        "._.",
        "Always, except in bed",
        "Only in bed",
        NULL
    }
    },
    {"really",
    {
        "Yes",
        "No",
        "idk",
        "maybe",
        "Yes really.",
        "Not really",
        "Of course",
        "yeah",
        "what do you think?",
        "uh huh",
        "Absolutely",
        "Yes sir",
        "Nope",
        "Positive",
        "Positively",
        NULL
    }
    },
    {"why are you",
    {
        "Cause I'm awesome",
        "I am programmed that way",
        "Ask the guy who coded me",
        "idk",
        "Because I am",
        "Why are you?",
        "Why not?",
        "Because...",
        "Cause I'm black",
        "Because I love candy",
        "Same reason as you.",
        "Who knows?",
        "The world may never know",
        NULL
    }
    },
    {"why ",
    {
        "You tell me",
        "Because I said so",
        "Why not?",
        "Becuase it just is",
        "Because I programmed it that way",
        "idk",
        "because...",
        "Just google it",
        "I'm not ChaCha answers",
        "I'm not an astrophysicist",
        "I'm not wikipedia",
        "RTFM",
        "Who knows",
        "The world may never know",
        "Some things are best left unexplained",
        "Why are you asking me???",
        "This is not tech support",
        "It's quite logical actually",
        "The answer is simple",
        NULL
    }
    },
    {"will you",
    {
        "Yes",
        "No",
        "maybe",
        "idk",
        "Eventually",
        "Of course",
        "someday i will",
        "Only if you will",
        "Absolutely",
        "Yeah",
        "When I feel like it",
        "As soon as I'm done with your mom",
        "I'd be happy to",
        "That's what I'm here for",
        "Absolutely not",
        "Only if you're willing to pay",
        "I'm not sure",
        "That sounds hard",
        "Why should I?",
        "Do it yourself.",
        "Yes, but I'll need more gunpowder.",
        "As soon as I can get more magnets",
        "I'm going to need liquid nitrogen to do that",
        "How am I supposed to do that?",
        "How am I supposed to do that without Uranium?",
        NULL
    }
    },
    {"*",
    {
        "Awesome",
        "Ok",
        "Interesting",
        "Okie Dokie",
        "Right",
        "wow",
        "That's funny",
        "I don't care",
        "That's weird",
        "Why?",
        "lol",
        "cool story bro",
        "How delightful",
        "Oh goodie",
        "borrrrring",
        "That's cool",
        "and?",
        "I'll keep that in mind",
        "I'll try to remember that",
        "Why would you say that?",
        "No really?",
        "That's what she said",
        "whatever",
        "Are you serious?",
        "Are you kidding me?",
        "Me too",
        "I know",
        "I didn't know that",
        "That's scary",
        "Sounds delicious",
        "You're making me hungry",
        "That's creepy",
        "That's wonderful!",
        "That's horrible",
        "Of course",
        "I knew it",
        "Shutup",
        "Great",
        "STFU",
        "In your face",
        "I told you so",
        "wtf",
        "0_o",
        ":)",
        ":D",
        "D:",
        "-_-",
        ">_<",
        "0_0",
        "hmm",
        ".........................",
        "...",
        "^_^",
        NULL
    }
    },
    {NULL, NULL}
};
 

Resolve TinyURLs

This will take tinyurls and output the real address of the location they point to.

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#endif
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;

int main(int argc, char ** argv) {
	if (argc != 2) {
		cout <<
			"URL Lengthener by Jakash3\n"
			"Usage: " << argv[0] << " URL\n";
		return 1;
	}
	int i;
	string url(argv[1]);
	char buf[512];
	struct addrinfo hints, *ai;
#ifdef _WIN32
	SOCKET sock;
	
	struct WSAData * wd;
	wd = (struct WSAData*)malloc(sizeof(struct WSAData));
	if (WSAStartup(MAKEWORD(2, 0), wd)) {
		cout << "Failed to initialize winsock api." << endl;
		free(wd);
		return 1;
	}
	free(wd);
#else
	int sock;
#endif
	
	if (url.find("http://") == 0) url.erase(0, 7);
	url += " HTTP/1.1\r\nHost: ";
	url += url.substr(0, url.find('/')) += "\r\n\r\n";
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	if ((i = getaddrinfo(url.substr(0, url.find('/')).c_str(), "80", &hints, &ai))) {
		cout << gai_strerror(i) << endl;
		return 1;
	}
	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
	if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) {
		cout << "Failed to connect." << endl;
		return 1;
	}
	freeaddrinfo(ai);
	url.insert(url.find('/'), "GET ");
	url.erase(0, url.find("GET "));
	send(sock, url.c_str(), url.size(), 0);
	for (;;) {
		for (i = 0; ; i++) {
			recv(sock, &(buf[i]), 1, 0);
			if (i >= 1);
			if (buf[i] == '\n' && buf[i - 1] == '\r') break;
		}
		buf[++i] = 0;
		if (!strcmp(buf, "\r\n")) {
			cout << "Host is not a url shortening service." << endl;
#ifdef _WIN32
			closesocket(sock);
			WSACleanup();
#else
			close(sock);
#endif
			return 1;
		}	
		if (!strncmp(buf, "Location: ", 10)) break;
	}
	*(strchr(buf, '\r')) == 0;
	memmove(buf, buf + 10, strlen(buf + 10) + 1);
	cout << buf << endl;
#ifdef _WIN32
	closesocket(sock);
	WSACleanup();
#else
	close(sock);
#endif
	return 0;
}

DLL Injection

Download source and binary: mediafire

DLL Injection is the process of making another program at runtime execute code by loading a dll in it. When the dll is loaded, it’s DLLMain function will be executed. This CLI tool will do so by opening the process with OpenProcess, allocating memory and writing the dll string in that process using VirtualAllocEx and WriteProcessMemory, and loading the DLL using CreateRemoteThread on LoadLibraryA with the argument pointing to the allocated dll string to load.

Source:

#include <windows.h>
#include <tlhelp32.h>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <stdexcept>
using namespace std;

/* 
* DLL Injection function - by Jakash3
* Thanks to Sri Krishna for his injection
* tutorial.
*
* program can be a pid in string form or
* an image name (in which case the first
* process found with the matching image
* name will be selected).
* 
* Returns handle to remote executing thread
*/
HANDLE dllinject(const char* program, const char* dll) {
	int i;
	DWORD pid;
	HANDLE h, t;
	LPVOID mem;
	PROCESSENTRY32 p;
	p.dwSize = sizeof(PROCESSENTRY32);
	
	//If all characters are numeric, program is a pid
	for (i = 0; program[i]; i++)
		if (!isdigit(program[i])) break;
	//If it's an imagename, find the first matching process
	if (i < strlen(program)) {
		if ((h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE)
			throw runtime_error("Failed to query processes");
		for (
		Process32First(h, &p);
		GetLastError() != ERROR_NO_MORE_FILES;
		Process32Next(h, &p))
			if (!strcmp(p.szExeFile, program)) {
				pid = p.th32ProcessID;
				break;
			}
		CloseHandle(h);
	} else pid = atoi(program);
	
	//Open process by pid
	if ((h = OpenProcess(
	PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
	PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION,
	false, pid)) == NULL)
		throw runtime_error("Failed to open process");
	
	//Allocate and write dll string in it
	mem = VirtualAllocEx(h, 0, strlen(dll) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
	if (mem == NULL) { CloseHandle(h); throw runtime_error("Failed to allocate dll string"); }
	WriteProcessMemory(h, mem, dll, strlen(dll) + 1, NULL);
	
	//Load dll into process
	if ((
	t = CreateRemoteThread(h, NULL, NULL,
	(LPTHREAD_START_ROUTINE)LoadLibraryA,
	mem, NULL, NULL)) == NULL) { 
		CloseHandle(h);
		throw runtime_error("Failed to execute remote thread");
	}
	
	//Free string and close
	Sleep(100);
	VirtualFreeEx(h, mem, NULL, MEM_RELEASE);
	CloseHandle(h);
	return t;
}

int main(int argc, char ** argv) {
	if (argc != 3) {
		printf(
			"DLL Injector by Jakash3\n"
			"Usage: %s PROGRAM DLL\n"
			"   PROGRAM - Image name or PID\n"
			"   DLL - DLL to load and execute entry point code\n",
			argv[0]
		);
		return 1;
	}
	try { dllinject(argv[1], argv[2]); } catch (exception& ex) {
		printf("Error: %s\nError code: %d\n", ex.what(), GetLastError());
		return 1;
	}
	puts("Success");
	return 0;
}

String to floating-point implementation

While working on an implementation of a scanf-like method for an input stream class, I realized that I needed to also implement a string to floating-point function to be used by this method for converting the read floating-point input string. Like my stoi template function, I created this stof template function that can convert a string to a float, double, or long double. While this function does detect overflows and underflows, it doesn’t do so perfectly and may sometimes miss some of those errors, resulting in a value of INF or NaN.

#include <cctype>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <cfloat>
#include <iostream>
using namespace std;

/* float, double, or long double */
template <typename type>
type stof(const char* s) {
	int i;
	type \
		ret = 0,			//Final return value
		num = 0,			//accumulator
		place = 1;		//digit place 10's value
	bool neg = false;	//Negative or positive number			
	const char *t;
	bool pineapple = false;		//Tells if we are calculating the whole or fractional part
	
	while (isspace(*s)) s++;	//Skip whitespace
	
	if (*s == '-') { neg = true; s++; }		//Check for negative
	else if (*s == '+') s++;
	
	if ((t = strchr(s, '.')) == NULL)		//Find first digit of the whole number part
		if ((t = strchr(s, 'e')) == NULL)
			t = s + strlen(s);
			
	for (t--; t >= s; t--, place *= 10) {	//Calculate the whole number part
		goto stof_smoothie;
		stof_forloop_1: ;
	}
	
	//Skip if no decimal point
	if ((t = strchr(s, '.')) == NULL) goto stof_blend_ice;
	
	//Calculate the fractional part
	pineapple = true;
	//Loop through each number after decimal point.
	//I didn't use isdigit in the for loop compare because
	//later on i have to check if it's a valid digit
	//and poop out an error if it's not.
	for (t++, place = 0.1;
		*t != 'e' && *t != 0;
	t++, place /= 10) {
		goto stof_smoothie;
		stof_forloop_2: ;
	}
	
stof_blend_ice:
	if ((t = strchr(s, 'e')) == NULL)
		return ret;
		
	//Multiply by 10^x if suffixed with 'e'
	else {
	//Where x comes right after e
		i = atoi(t + 1);
	//Divide by 10s if negative
		if (i < 0) {
			for (; i < 0; i++) {
				num = ret / 10;
	//Dividing should make a smaller number, if not...there was an underflow
				if (num >= ret) throw underflow_error("underflow");
				else ret = num;
			}
		} else {
	//Multiply by 10s if positive
			for (; i > 0; i--) {
				num = ret * 10;
	//Multiplying should make a bigger number, if not...there was an overflow
				if (num <= ret) throw overflow_error("overflow 0");
				else ret = num;
			}
		}
	}
	return ret;

//Performed in both loops where the whole and fractional
//parts are calculated. I know goto is considered bad
//but this time it's just genius. I save more space this
//way
stof_smoothie:

//Not sure if this applies to floating numbers
//but place value would loop back to 0 if there
//was an over/underflow
	if (!place)
		if (neg) throw underflow_error("underflow");
		else throw overflow_error("overflow 1");

//Validate and convert digit
	if (!isdigit(*t)) throw invalid_argument("Invalid string");
	num = (*t - '0') * place;
	
//Basically, it's an overflow or underflow if the result is not logical
	if (neg) {
		if ((type)(ret - (num ? num : place) > ret))
			throw underflow_error("underflow");
		ret -= num;
		if (ret >= 0 && num != 0) throw underflow_error("underflow");
	} else {
		if ((type)(ret + (num ? num : place) <= ret)) throw overflow_error("overflow 2");
			ret += num;
		if (ret <= 0 && num != 0) throw overflow_error("overflow 3");
	}
	if (pineapple) goto stof_forloop_2;
	else goto stof_forloop_1;
}

int main() {
	cout << stof<float>("3.14e-8") << endl;
}

String to integer implementation

#include <climits>
#include <cctype>
#include <typeinfo>
#include <iostream>
#include <cstdlib>
#include <cstring>

template <typename type>
type stoi(const char* s, int base);

int main() {
	short i;
	char buf[512];
	std::cout << 
		"SHRT_MIN = " << SHRT_MIN << std::endl <<
		"SHRT_MAX = " << SHRT_MAX << std::endl <<
		"Input short: ";
	std::cin >> buf;
	try {
		i = stoi<short>(buf, 0);
	} catch (int x) {
		std::cout << "Error: ";
		switch (x) {
		case 0: std::cout << "Invalid number\n"; break;
		case 1: std::cout << "Overflow\n"; break;
		case -1: std::cout << "Underflow\n"; break;
		}
		return 1;
	}
	std::cout << i << std::endl;
}

/*
* String to Integral type function
* by Jakash3
* Thu Jul 14, 2011
*
* Desc: When calling this function, the
* template type must be a built-in numeric
* type. Valid types are: char, short, int,
* long, long long, and their equivalent
* unsigned types.
* 
* s is the string to convert, base is the
* numeric base to use.
*
* s may have any amount of leading whitespace
* followed by an optional '+' or '-' sign.
* If base is 16 or 8 then the string may also
* have an optional "0x" or "0" prefix (after
* the sign if present). If base is 0 then
* the base will default to 10, 16, or 8 based
* on the base prefix (if present). 
*
* On success the number of the template type
* will be returned. This function will throw
* an exception of type int on failure. If it
* throws 0 then the string contained invalid
* characters, if it throws -1 then there was
* an underflow, if it throws 1 then there
* was an overflow.
*/
template <typename type>
type stoi(const char* s, int base) {
	bool neg = false;		//Negative flag
	type \
		ret = 0,				//Converted return value
		num,					//Temporary
		place = 1;			//Current digit place
		
	//What integer type are we converting to?
	const std::type_info &ti = typeid(type);
	
	//Skip whitespace
	while (isspace(*s)) s++;
	
	//Check for sign
	if (*s == '-') { neg = true; s++; }
	else if (*s == '+') s++;
	
	//Match optional base prefixes
	if (base == 0) {
		if (*s == '0') {
			if (tolower(s[1]) == 'x') { base = 16; s += 2; }
			else { base = 8; s++; }
		} else base = 10;
	} else {
		if (*s == '0') {
			if (tolower(s[1]) == 'x' && base == 16) s += 2;
			else if (base == 8) s++;
			else throw 0;
		}
	}
	
	const char \
		*set = "0123456789abcdefghijklmnopqrstuvwxyz",
		*t = s + strlen(s) - 1,
		*tmp;
	
	//For each digit in string (starting from rightmost)
	for (; t >= s; t--, place *= base) {
	
	//If place is 0 then value of digit place overflowed
		if (!place)
			if (neg) throw -1;
			else throw 1;
	
		//Get digit offset
		tmp = strchr(set, tolower(*t));
		
		//Is this a valid digit?
		if (tmp == NULL) throw 0;
		if (tmp - set >= base) throw 0;
		
		//Convert to digit value
		num = (tmp - set) * place;

		if (neg) {
			//Check for unsigned underflow
			if ((type)(ret - (num ? num : place) > ret)) throw -1;
			ret -= num;
			//Check for signed overflow
			if (ret >= 0 && num != 0) throw -1;
		} else {
			//Check for unsigned overflow
			if ((type)(ret + (num ? num : place) < ret)) throw 1;
			ret += num;
			//Check for signed overflow
			if (ret <= 0 && num != 0) throw 1;
		}
	}
	return ret;
}

int getRandomNumber() {
	return 4;		//chosen by fair dice roll.
						//guaranteed to be random.
}

This sample program uses my string to numeric function. This is more advanced as it supports negative numbers, multiple numeric datatypes (a template function), and supports try … catch for error handling.
/*
* String to Integral type function
* by Jakash3
* Thu Jul 14, 2011
*
* Desc: When calling this function, the
* template type must be a built-in numeric
* type. Valid types are: char, short, int,
* long, long long, and their equivalent
* unsigned types.
* 
* s is the string to convert, base is the
* numeric base to use.
*
* s may have any amount of leading whitespace
* followed by an optional '+' or '-' sign.
* If base is 16 or 8 then the string may also
* have an optional "0x" or "0" prefix (after
* the sign if present). If base is 0 then
* the base will default to 10, 16, or 8 based
* on the base prefix (if present). 
*
* On success the number of the template type
* will be returned. This function will throw
* an exception of type int on failure. If it
* throws 0 then the string contained invalid
* characters, if it throws -1 then there was
* an underflow, if it throws 1 then there
* was an overflow.
*/