roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
 /*
 * vprint.cpp
 *	 Functions related to vprint (printf replacement for realms)
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "login.h"
#include "vprint.h"
#define __CYGWIN__
#include <stdarg.h>

// Function Prototypes
bstring delimit(const char *str, int wrap);

void Creature::bPrint(bstring toPrint) const {
	printColor("%s", toPrint.c_str());
}

void Creature::print(const char *fmt,...) const {
	// Mad hack, but it'll stop some stupid errors
	if(!this)
		return;

	Socket* printTo = getSock();

	if(isPet())
		printTo = getConstMaster()->getSock();

	if(!this || !printTo)
		return;

	va_list ap;

	va_start(ap, fmt);
	if(isPet()) {
		printTo->print("Pet> ");
	}
	printTo->vprint(fmt, ap);
	va_end(ap);
}

void Creature::printColor(const char *fmt,...) const {
	Socket* printTo = getSock();

	if(isPet())
		printTo = getConstMaster()->getSock();

	if(!this || !printTo)
		return;

	va_list ap;

	va_start(ap, fmt);
	if(isPet()) {
		printTo->print("Pet> ");
	}
	printTo->vprint(fmt, ap);
	va_end(ap);
}
void Player::vprint(const char *fmt, va_list ap) const {
	if(this && mySock)
		mySock->vprint(fmt, ap);
}


#if !defined(__CYGWIN__) && !defined(__MACOS__)
// vprint, called by print and other variable argument print functions
// absolutely not thread safe ;)

static int VPRINT_flags = 0;

void Socket::vprint(const char *fmt, va_list ap) {
	char	*msg;
	va_list	aq;

	if(!this) {
		std::cout << "vprint(): called with null this! :(\n";
		return;
	}

	VPRINT_flags = 0;
	if(myPlayer)
		VPRINT_flags = myPlayer->displayFlags();
	// Incase vprint is called multiple times with the same ap
	// (in which case ap would be undefined, so make a copy of it
	va_copy(aq, ap);
	int n = vasprintf(&msg, fmt, aq);
	va_end(aq);

	if(n == -1) {
		std::cout << "Problem with vasprintf in vprint!" << std::endl;
		return;
	}
	bstring toPrint;

    if(!myPlayer || (myPlayer && myPlayer->getWrap() == -1))
        toPrint = delimit( msg, getTermCols() - 4);
    else if(myPlayer && myPlayer->getWrap() > 0)
        toPrint = delimit( msg, myPlayer->getWrap());
    else
        toPrint = msg;
    toPrint += "^x";
    bprint(toPrint);

	free(msg);
}

int print_objcrt(FILE *stream, const struct printf_info *info, const void *const *args) {
	char *buffer;
	int len;

	if(info->spec == 'B') {
		const bstring *tmp = *((const bstring **) (args[0]));
		len = asprintf(&buffer, "%s", tmp->c_str());
	}
	else if(info->spec == 'T') {
		const std::ostringstream *tmp = *((const std::ostringstream **) (args[0]));
		len = asprintf(&buffer, "%s", tmp->str().c_str());
	}
	// M = Capital Monster N = small monster
	else if(info->spec == 'M' || info->spec == 'N') {
		const Creature *crt = *((const Creature **) (args[0]));
		if(info->spec == 'M') {
		    bstring tmp = crt->getCrtStr(NULL, VPRINT_flags | CAP, info->width);
			len = asprintf(&buffer, "%s", tmp.c_str());
		}
		else {
		    bstring tmp = crt->getCrtStr(NULL, VPRINT_flags, info->width);
			len = asprintf(&buffer, "%s", tmp.c_str());
		}
		if(len == -1)
			return(-1);
	}
	else if(info->spec == 'R') {
		const Creature *crt = *((const Creature **) (args[0]));
		len = asprintf(&buffer, "%s", crt->getCName());
		if(len == -1)
			return(-1);
	}
	// O = Capital Object P = small object
	else if(info->spec == 'O' || info->spec == 'P') {
		const Object *obj = *((const Object **) (args[0]));
		if(info->spec == 'O') {
		    bstring tmp = obj->getObjStr(NULL, VPRINT_flags | CAP, info->width);
			len = asprintf(&buffer, "%s", tmp.c_str());
		}
		else {
		    bstring tmp = obj->getObjStr(NULL, VPRINT_flags, info->width);
			len = asprintf(&buffer, "%s", tmp.c_str());
		}

		if(len == -1)
			return(-1);
	}
	// Unhandled type
	else {
		return(-1);
	}

	// Pad to the minimum field width and print to the stream.
	//len = fprintf (stream, "%*s", (info->left ? -info->width : info->width), buffer);
	len = fprintf(stream, "%s", buffer);

	// Clean up and return.
	free(buffer);
	return(len);
}

int print_arginfo (const struct printf_info *info, size_t n, int *argtypes) {
	// We always take exactly one argument and this is a pointer to the structure..
	if(n > 0)
		argtypes[0] = PA_POINTER;
	return(1);
}

int Server::installPrintfHandlers() {
	int r = 0;
	// bstring
	r |= register_printf_function('B', print_objcrt, print_arginfo);
	// std::ostringstream
	r |= register_printf_function('T', print_objcrt, print_arginfo);
	// creature
	r |= register_printf_function('N', print_objcrt, print_arginfo);
	// capital creature
	r |= register_printf_function('M', print_objcrt, print_arginfo);
	// object
	r |= register_printf_function('P', print_objcrt, print_arginfo);
	// capital object
	r |= register_printf_function('O', print_objcrt, print_arginfo);
	// creature's real name
	r |= register_printf_function('R', print_objcrt, print_arginfo);
	return(r);
}

#else


// vprint, only used on cygwin
//
void Socket::vprint(const char *fmt, va_list ap) {
	char	msg[8192];
	char	*fmt2;
	int		i = 0, j = 0, k;
	int		num, loc, ind = -1, len, flags = 0;
	void*		arg[14];
	char	type;


	if(myPlayer)
		flags = myPlayer->displayFlags();

	len = strlen(fmt);
	fmt2 = new char[len+1];
	if(!fmt2)
		merror("print", FATAL);

	arg[0] = va_arg(ap, void*);
	arg[1] = va_arg(ap, void*);
	arg[2] = va_arg(ap, void*);
	arg[3] = va_arg(ap, void*);
	arg[4] = va_arg(ap, void*);
	arg[5] = va_arg(ap, void*);
	arg[6] = va_arg(ap, void*);
	arg[7] = va_arg(ap, void*);
	arg[8] = va_arg(ap, void*);
	arg[9] = va_arg(ap, void*);
	arg[10] = va_arg(ap, void*);
	arg[11] = va_arg(ap, void*);
	arg[12] = va_arg(ap, void*);
	arg[13] = va_arg(ap, void*);


	// Check for special handlers and modify arguments as necessary
	do {
		if(fmt[i] == '%') {
			fmt2[j++] = fmt[i];
			num = 0;
			k = i;
			do {
				k++;
				if(	(fmt[k] >= 'a' && fmt[k] <= 'z') ||
					(fmt[k] >= 'A' && fmt[k] <= 'Z') ||
					fmt[k] == '%'
				) {
					loc = k;
					type = fmt[k];
					break;
				} else if(fmt[k] >= '0' && fmt[k] <= '9')
					num = num * 10 + fmt[k] - '0';
			} while(k < len);

			if(type == '%') {
				fmt2[j++] = '%';
				i++;
				i++;
				continue;
			}

			ind++;
			if(	type != 'N' &&	// creature
				type != 'M' &&	// capital creature
				type != 'O' &&	// capital object
				type != 'P' &&	// object
				type != 'R' &&	// creature's real name
				type != 'B' &&	// bstring
				type != 'T'		// ostringstream
			) {
				i++;
				continue;
			}

			i = loc + 1;
			fmt2[j++] = 's';

			switch (type) {
			case 'B':
				arg[ind] = (void*) ((bstring *) arg[ind])->c_str();
				continue;
			case 'T':
				arg[ind] = (void*) ((std::ostringstream *) arg[ind])->str().c_str();
				continue;
			case 'N':
				arg[ind] = (void*) ((Creature *)arg[ind])->getCrtStr(NULL, flags, num).c_str();
				continue;
			case 'M':
				arg[ind] = (void*) ((Creature *) arg[ind])->getCrtStr(NULL, flags | CAP, num).c_str();
				continue;
			case 'P':
				arg[ind] = (void*) ((Object *) arg[ind])->getObjStr(NULL, flags, num).c_str();
				continue;
			case 'O':
				arg[ind] = (void*) ((Object *) arg[ind])->getObjStr(NULL, flags | CAP, num).c_str();
				continue;
			case 'R':
				arg[ind] = (void*) (((Creature *)arg[ind])->getName().c_str());
				continue;
			}
		}
		fmt2[j++] = fmt[i++];
	} while(i < len);

	fmt2[j] = 0;
	snprintf(msg, 8000, fmt2, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10], arg[11], arg[12], arg[13], arg[14]);
	delete fmt2;


	bstring toPrint;

    toPrint = delimit( msg, getTermCols() - 4);
    bprint(toPrint);
}


#endif