/* * 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