00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "pent_include.h"
00023 #include "ODataSource.h"
00024 #include "RenderSurface.h"
00025 #include "util.h"
00026 #include "FixedWidthFont.h"
00027
00028 #include <cstdio>
00029 #include <cstring>
00030 #include <cstdlib>
00031 #include <cstdarg>
00032
00033 using namespace std;
00034
00035 #define MAXPRINTMSG 4096
00036
00037
00038 Console con;
00039
00040
00041
00042
00043 #ifndef SAFE_CONSOLE_STREAMS
00044 console_ostream<char> pout;
00045 console_ostream<char> *ppout = &pout;
00046 #else
00047 console_ostream<char> *ppout = 0;
00048 #endif
00049
00050
00051 #ifndef SAFE_CONSOLE_STREAMS
00052 console_err_ostream<char> perr;
00053 console_err_ostream<char> *pperr = &perr;
00054 #else
00055 console_err_ostream<char> *pperr = 0;
00056 #endif
00057
00058
00059
00060
00061
00062
00063
00064 void Console::Clear ()
00065 {
00066 std::memset (text, ' ', CON_TEXTSIZE);
00067 putchar_count = 0;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 void Console::Dump (const char *name)
00079 {
00080 int l, x;
00081 char *line;
00082 FILE *f;
00083 char buffer[1024];
00084
00085
00086 PrintPutchar();
00087
00088 Printf ("Dumped console text to %s.\n", name);
00089 f = std::fopen (name, "wa");
00090 if (!f)
00091 {
00092 Print ("ERROR: couldn't open.\n");
00093 return;
00094 }
00095
00096
00097 for (l = current - totallines + 1 ; l <= current ; l++)
00098 {
00099 line = text + (l%totallines)*linewidth;
00100 for (x=0 ; x<linewidth ; x++)
00101 if (line[x] != ' ')
00102 break;
00103 if (x != linewidth)
00104 break;
00105 }
00106
00107
00108 buffer[linewidth] = 0;
00109 for ( ; l <= current ; l++)
00110 {
00111 line = text + (l%totallines)*linewidth;
00112 std::strncpy (buffer, line, linewidth);
00113 for (x=linewidth-1 ; x>=0 ; x--)
00114 {
00115 if (buffer[x] == ' ')
00116 buffer[x] = 0;
00117 else
00118 break;
00119 }
00120 for (x=0; buffer[x]; x++)
00121 buffer[x] &= 0x7f;
00122
00123 std::fprintf (f, "%s\n", buffer);
00124 }
00125
00126 std::fclose (f);
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 void Console::CheckResize (int scrwidth)
00138 {
00139 int i, j, width, oldwidth, oldtotallines, numlines, numchars;
00140 char tbuf[CON_TEXTSIZE];
00141
00142
00143 PrintPutchar();
00144
00145 if (!confont)
00146 width = (scrwidth >> 3) - 2;
00147 else
00148 width = (scrwidth / confont->width) - 2;
00149
00150 if (width == linewidth)
00151 return;
00152
00153 if (width < 1)
00154 {
00155 width = 78;
00156 linewidth = width;
00157 totallines = CON_TEXTSIZE / linewidth;
00158 std::memset (text, ' ', CON_TEXTSIZE);
00159 }
00160 else
00161 {
00162 oldwidth = linewidth;
00163 linewidth = width;
00164 oldtotallines = totallines;
00165 totallines = CON_TEXTSIZE / linewidth;
00166 numlines = oldtotallines;
00167
00168 if (totallines < numlines)
00169 numlines = totallines;
00170
00171 numchars = oldwidth;
00172
00173 if (linewidth < numchars)
00174 numchars = linewidth;
00175
00176 std::memcpy (tbuf, text, CON_TEXTSIZE);
00177 std::memset (text, ' ', CON_TEXTSIZE);
00178
00179 for (i=0 ; i<numlines ; i++)
00180 {
00181 for (j=0 ; j<numchars ; j++)
00182 {
00183 text[(totallines - 1 - i) * linewidth + j] =
00184 tbuf[((current - i + oldtotallines) %
00185 oldtotallines) * oldwidth + j];
00186 }
00187 }
00188 }
00189
00190 current = totallines - 1;
00191 display = current;
00192 }
00193
00194
00195
00196
00197 Console::Console () : current(0), x(0), display(0), linewidth(-1),
00198 totallines(0), vislines(0), wordwrap(true), cr(false),
00199 putchar_count(0), std_output_enabled(0xFFFFFFFF),
00200 stdout_redir(0), stderr_redir(0), confont(0),
00201 auto_paint(0), msgMask(MM_ALL), framenum(0),
00202 commandCursorPos(0), commandInsert(true), commandHistoryPos(0)
00203 {
00204 linewidth = -1;
00205
00206 CheckResize (0);
00207
00208 std::memset (times, 0, sizeof(times));
00209
00210
00211 AddConsoleCommand("Console::CmdList", ConCmd_CmdList);
00212 AddConsoleCommand("Console::CmdHistory", ConCmd_CmdHistory);
00213
00214 PrintInternal ("Console initialized.\n");
00215 }
00216
00217
00218
00219
00220 Console::~Console()
00221 {
00222 RemoveConsoleCommand(Console::ConCmd_CmdList);
00223 RemoveConsoleCommand(Console::ConCmd_CmdHistory);
00224
00225
00226 PrintPutchar();
00227 }
00228
00229
00230
00231
00232
00233
00234
00235 void Console::PrintInternal (const char *txt)
00236 {
00237 int y;
00238 int c, l;
00239
00240
00241 PrintPutchar();
00242
00243 while ( 0 != (c = *txt) )
00244 {
00245 if (wordwrap) {
00246
00247 for (l=0 ; l< linewidth ; l++)
00248 if ( txt[l] <= ' ')
00249 break;
00250
00251
00252 if (l != linewidth && (x + l > linewidth) )
00253 x = 0;
00254 }
00255
00256 txt++;
00257
00258 if (cr)
00259 {
00260 current--;
00261 cr = false;
00262 }
00263
00264 if (!x)
00265 {
00266 Linefeed ();
00267
00268 if (current >= 0) times[current % CON_NUM_TIMES] = framenum;
00269 }
00270
00271 switch (c)
00272 {
00273 case '\n':
00274 x = 0;
00275 break;
00276
00277 case '\r':
00278 x = 0;
00279 cr = true;
00280 break;
00281
00282 default:
00283 y = current % totallines;
00284 text[y*linewidth+x] = static_cast<char>(c);
00285 x++;
00286 if (x >= linewidth) x = 0;
00287 break;
00288 }
00289
00290 }
00291 }
00292
00293
00294 void Console::PrintRawInternal (const char *txt, int n)
00295 {
00296 int y;
00297 int c, l;
00298
00299
00300 PrintPutchar();
00301
00302 for ( int i = 0; i < n; i++ )
00303 {
00304 c = *txt;
00305
00306 if (wordwrap) {
00307
00308 for (l=0 ; l < linewidth && l < n; l++)
00309 if ( txt[l] <= ' ') break;
00310
00311
00312 if (l != linewidth && (x + l > linewidth) )
00313 x = 0;
00314 }
00315
00316 txt++;
00317
00318 if (cr)
00319 {
00320 current--;
00321 cr = false;
00322 }
00323
00324 if (!x)
00325 {
00326 Linefeed ();
00327
00328 if (current >= 0) times[current % CON_NUM_TIMES] = framenum;
00329 }
00330
00331 switch (c)
00332 {
00333 case '\n':
00334 x = 0;
00335 break;
00336
00337 case '\r':
00338 x = 0;
00339 cr = true;
00340 break;
00341
00342 default:
00343 y = current % totallines;
00344 text[y*linewidth+x] = static_cast<char>(c);
00345 x++;
00346 if (x >= linewidth) x = 0;
00347 break;
00348 }
00349
00350 }
00351 }
00352
00353
00354 void Console::Linefeed (void)
00355 {
00356 x = 0;
00357 display++;
00358 current++;
00359 std::memset (&text[(current%totallines)*linewidth], ' ', linewidth);
00360
00361 if (auto_paint) auto_paint();
00362 }
00363
00364
00365 void Console::PutcharInternal (int c)
00366 {
00367
00368 putchar_buf[putchar_count] = static_cast<char>(c);
00369
00370
00371 putchar_count++;
00372
00373
00374
00375 if (c <= ' ' || putchar_count == (CON_PUTCHAR_SIZE-1)) PrintPutchar();
00376 }
00377
00378
00379 void Console::PrintPutchar()
00380 {
00381 if (!putchar_count) return;
00382
00383
00384
00385
00386
00387 putchar_buf[putchar_count] = 0;
00388
00389
00390 putchar_count = 0;
00391
00392
00393 PrintInternal(putchar_buf);
00394 }
00395
00396
00397
00398
00399
00400
00401 void Console::Print(const char *txt)
00402 {
00403 if (std_output_enabled & CON_STDOUT) fputs(txt, stdout);
00404 if (stdout_redir) stdout_redir->write(txt, std::strlen(txt));
00405 PrintInternal(txt);
00406 }
00407
00408
00409 void Console::Print(const MsgMask mm, const char *txt)
00410 {
00411 if(mm & msgMask) Print(txt);
00412 }
00413
00414
00415 sint32 Console::Printf(const char *fmt, ...)
00416 {
00417 va_list argptr;
00418
00419 va_start(argptr,fmt);
00420 sint32 count = vPrintf(fmt, argptr);
00421 va_end(argptr);
00422
00423 return count;
00424 }
00425
00426
00427 sint32 Console::Printf(const MsgMask mm, const char *fmt, ...)
00428 {
00429 if(!(mm & msgMask)) return 0;
00430
00431 va_list argptr;
00432
00433 va_start(argptr,fmt);
00434 sint32 count = vPrintf(fmt, argptr);
00435 va_end(argptr);
00436
00437 return count;
00438 }
00439
00440
00441 sint32 Console::vPrintf (const char *fmt, va_list argptr)
00442 {
00443 char msg[MAXPRINTMSG];
00444
00445 if (std_output_enabled & CON_STDOUT) {
00446 va_list argptr2;
00447 va_copy(argptr2, argptr);
00448 vfprintf (stdout, fmt, argptr2);
00449 va_end(argptr2);
00450 }
00451 sint32 count = vsnprintf (msg, MAXPRINTMSG, fmt, argptr);
00452 if (stdout_redir) stdout_redir->write(msg, count);
00453 PrintInternal(msg);
00454
00455 return count;
00456 }
00457
00458
00459 void Console::PrintRaw (const char *txt, int n)
00460 {
00461 if (std_output_enabled & CON_STDOUT) std::fwrite(txt, n, 1, stdout);
00462 if (stdout_redir) stdout_redir->write(txt, n);
00463 PrintRawInternal (txt, n);
00464 }
00465
00466
00467 void Console::Putchar (int c)
00468 {
00469 if (std_output_enabled & CON_STDOUT) fputc(c, stdout);
00470 if (stdout_redir) stdout_redir->write1(c);
00471 PutcharInternal(c);
00472 }
00473
00474
00475
00476
00477
00478
00479
00480 void Console::Print_err (const char *txt)
00481 {
00482 if (std_output_enabled & CON_STDERR) fputs(txt, stderr);
00483 if (stderr_redir) stderr_redir->write(txt, std::strlen(txt));
00484 PrintInternal (txt);
00485 }
00486
00487
00488 void Console::Print_err(const MsgMask mm, const char *txt)
00489 {
00490 if(mm & msgMask) Print_err(txt);
00491 }
00492
00493
00494 sint32 Console::Printf_err (const char *fmt, ...)
00495 {
00496 va_list argptr;
00497
00498 va_start (argptr, fmt);
00499 sint32 count = vPrintf_err(fmt, argptr);
00500 va_end (argptr);
00501
00502 return count;
00503 }
00504
00505
00506 sint32 Console::Printf_err(const MsgMask mm, const char *fmt, ...)
00507 {
00508 if(!(mm & msgMask)) return 0;
00509
00510 va_list argptr;
00511
00512 va_start(argptr,fmt);
00513 sint32 count = vPrintf_err(fmt, argptr);
00514 va_end(argptr);
00515
00516 return count;
00517 }
00518
00519
00520 sint32 Console::vPrintf_err (const char *fmt, va_list argptr)
00521 {
00522 char msg[MAXPRINTMSG];
00523
00524 if (std_output_enabled & CON_STDERR) {
00525 va_list argptr2;
00526 va_copy(argptr2, argptr);
00527 vfprintf (stderr, fmt, argptr2);
00528 va_end(argptr2);
00529 }
00530 sint32 count = vsnprintf (msg, MAXPRINTMSG, fmt, argptr);
00531 if (stderr_redir) stderr_redir->write(msg, count);
00532 PrintInternal (msg);
00533
00534 return count;
00535 }
00536
00537
00538 void Console::PrintRaw_err (const char *txt, int n)
00539 {
00540 if (std_output_enabled & CON_STDERR) std::fwrite(txt,n,1,stderr);
00541 if (stderr_redir) stderr_redir->write(txt, n);
00542 PrintRawInternal (txt, n);
00543 }
00544
00545
00546 void Console::Putchar_err (int c)
00547 {
00548 if (std_output_enabled & CON_STDERR) fputc(c, stderr);
00549 if (stderr_redir) stderr_redir->write1(c);
00550 PutcharInternal(c);
00551 }
00552
00553 void Console::ScrollConsole(sint32 lines)
00554 {
00555 display += lines;
00556
00557 if (display < 0) display = 0;
00558 if (display > current) display = current;
00559 }
00560
00561
00562
00563
00564
00565 void Console::AddConsoleCommand(const ArgsType &command, Console::Function function)
00566 {
00567 ConsoleCommands[command] = function;
00568 }
00569
00570 void Console::RemoveConsoleCommand(Console::Function function)
00571 {
00572 std::map<Console::ArgsType,Console::Function>::iterator it;
00573 for (it = ConsoleCommands.begin(); it != ConsoleCommands.end(); ++it)
00574 {
00575 if (it->second == function)
00576 {
00577
00578 it->second = 0;
00579 }
00580 }
00581 }
00582 void Console::ExecuteConsoleCommand(const Console::ArgsType &args)
00583 {
00584 Console::ArgvType argv;
00585 Pentagram::StringToArgv(args,argv);
00586
00587 ExecuteConsoleCommand(argv);
00588 }
00589
00590 void Console::ExecuteConsoleCommand(const Console::ArgvType &argv)
00591 {
00592 std::map<Console::ArgsType,Console::Function>::iterator it;
00593
00594
00595 if (argv.empty()) return;
00596
00597 it = ConsoleCommands.find(argv[0]);
00598
00599 if (it != ConsoleCommands.end())
00600 it->second(argv);
00601 else
00602 pout << "Unknown command: " << argv[0] << std::endl;
00603 }
00604
00605 void Console::ExecuteCommandBuffer()
00606 {
00607 if (commandBuffer.empty()) return;
00608
00609 Console::ArgsType args = commandBuffer;
00610 commandBuffer.clear();
00611
00612 pout << "]" << args << std::endl;
00613
00614 ExecuteConsoleCommand(args);
00615
00616 commandHistory.push_back(args);
00617 commandHistoryPos = 0;
00618 commandCursorPos = 0;
00619 }
00620
00621 void Console::ScrollCommandHistory(int num)
00622 {
00623 int total = commandHistory.size();
00624
00625
00626 if (!total) return;
00627
00628 if ((commandHistoryPos-num) <= 0)
00629 {
00630 if (commandHistoryPos == 1) return;
00631 commandHistoryPos = 1;
00632 }
00633 else
00634 commandHistoryPos -= num;
00635
00636 if (commandHistoryPos > total)
00637 commandHistoryPos = total;
00638
00639 commandBuffer = commandHistory[total-commandHistoryPos];
00640 commandCursorPos = commandBuffer.size();
00641 }
00642
00643 void Console::ClearCommandBuffer()
00644 {
00645 commandBuffer.clear();
00646 commandCursorPos = 0;
00647 }
00648
00649 void Console::AddCharacterToCommandBuffer(int ch)
00650 {
00651
00652 if (ch == Console::Enter) {
00653
00654 ExecuteCommandBuffer();
00655 }
00656
00657 else if (ch == Console::Backspace) {
00658
00659 DeleteCommandBufferChars(-1);
00660 }
00661
00662 else if (ch == Console::Tab) {
00663
00664 if (!commandBuffer.empty()) {
00665
00666 int count = 0;
00667 Console::ArgsType common;
00668 std::map<Console::ArgsType,Console::Function>::iterator it;
00669 std::map<Console::ArgsType,Console::Function>::iterator found;
00670
00671 for (it = ConsoleCommands.begin(); it != ConsoleCommands.end(); ++it)
00672 if (it->second) {
00673 if (it->first.compare(0, commandBuffer.size(), commandBuffer))
00674 continue;
00675
00676 if (!count)
00677 {
00678 common = it->first;
00679 found = it;
00680 }
00681 else
00682 {
00683 Console::ArgsType::iterator it1 = common.begin();
00684 Console::ArgsType::const_iterator it2 = it->first.begin();
00685 int comsize = 0;
00686
00687 while (it1 != common.end())
00688 {
00689 if (!Console::ArgsType::traits_type::eq(*it1,*it2)) break;
00690
00691 comsize++;
00692 ++it1;
00693 ++it2;
00694 }
00695
00696 common.resize(comsize);
00697 }
00698 count++;
00699 }
00700
00701 if (count)
00702 {
00703
00704 if (count > 1) {
00705 pout << "]" << commandBuffer << std::endl;
00706
00707 ArgsType args = "CmdList \"";
00708 args += commandBuffer;
00709 args += '\"';
00710
00711 ArgvType argv;
00712 Pentagram::StringToArgv(args,argv);
00713
00714 ConCmd_CmdList(argv);
00715 commandBuffer = common;
00716 }
00717 else
00718 commandBuffer = common;
00719
00720 commandCursorPos = commandBuffer.size();
00721 }
00722 }
00723 }
00724
00725 else {
00726
00727 if (commandCursorPos == static_cast<int>(commandBuffer.size()))
00728 {
00729 commandBuffer += ch;
00730 }
00731 else if (commandInsert)
00732 {
00733 commandBuffer.insert(commandCursorPos, 1, ch);
00734 }
00735 else
00736 {
00737 commandBuffer[commandCursorPos] = ch;
00738 }
00739
00740 commandCursorPos++;
00741 }
00742 }
00743
00744 void Console::DeleteCommandBufferChars(int num)
00745 {
00746 if (!num || commandBuffer.empty()) return;
00747
00748 if (num < 0)
00749 {
00750 num = -num;
00751 if (num > commandCursorPos) num = commandCursorPos;
00752 commandCursorPos -= num;
00753 }
00754 else
00755 {
00756 if ((num+commandCursorPos) > static_cast<int>(commandBuffer.size()))
00757 num = commandBuffer.size()-commandCursorPos;
00758 }
00759
00760 commandBuffer.erase(commandCursorPos, num);
00761 }
00762
00763 void Console::MoveCommandCursor(int num)
00764 {
00765 commandCursorPos += num;
00766
00767 if (commandCursorPos < 0) commandCursorPos = 0;
00768 if (commandCursorPos > static_cast<int>(commandBuffer.size())) commandCursorPos = static_cast<int>(commandBuffer.size());
00769 }
00770
00771 void Console::ConCmd_CmdList(const Console::ArgvType &argv)
00772 {
00773 std::map<ArgsType,Function>::iterator it;
00774 int i = 0;
00775
00776
00777
00778 if (argv.size() > 1)
00779 {
00780 for (std::size_t a = 1; a < argv.size(); a++)
00781 {
00782 const ArgsType &arg = argv[a];
00783
00784 for (it = con.ConsoleCommands.begin(); it != con.ConsoleCommands.end(); ++it)
00785 if (it->second) {
00786 if (it->first.compare(0, arg.size(), arg)) continue;
00787
00788 pout << " " << it->first << std::endl;
00789 i ++;
00790 }
00791 }
00792 }
00793 else
00794 {
00795 for (it = con.ConsoleCommands.begin(); it != con.ConsoleCommands.end(); ++it)
00796 if (it->second) {
00797 pout << " " << it->first << std::endl;
00798 i ++;
00799 }
00800 }
00801
00802 pout << i << " commands" << std::endl;
00803 }
00804
00805 void Console::ConCmd_CmdHistory(const Console::ArgvType & )
00806 {
00807 std::vector<ArgsType>::iterator it;
00808
00809 for (it = con.commandHistory.begin(); it != con.commandHistory.end(); ++it)
00810 pout << " " << *it << std::endl;
00811
00812 pout << con.commandHistory.size() << " commands" << std::endl;
00813 }
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823 void Console::DrawConsole (RenderSurface *surf, int height)
00824 {
00825 int i, x, y;
00826 int rows;
00827 int row;
00828 int lines;
00830
00831
00832 PrintPutchar();
00833
00834 lines = height;
00835 if (lines <= 0)
00836 return;
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846 vislines = lines;
00847
00848 #if 0
00849 rows = (lines-8)>>3;
00850
00851 y = lines - 24;
00852 #else
00853 rows = (lines/confont->height)-2;
00854
00855 y = lines - (confont->height*3);
00856 #endif
00857
00858
00859 if (display != current)
00860 {
00861
00862 for (x=0 ; x<linewidth ; x+=4)
00863 surf->PrintCharFixed(confont, '^', (x+1)*confont->width, y);
00864
00865 y -= confont->height;
00866 rows--;
00867 }
00868
00869 row = display;
00870 for (i=0 ; i<rows ; i++, y-=confont->height, row--)
00871 {
00872 if (row < 0)
00873 break;
00874 if (current - row >= totallines)
00875 break;
00876
00877 char *txt = text + (row % totallines)*linewidth;
00878
00879 for (x=0 ; x<linewidth ; x++) {
00880 surf->PrintCharFixed(confont, txt[x], (x+1)*confont->width, y);
00881
00882 }
00883
00884 }
00885
00886 const char *com = commandBuffer.c_str();
00887 int com_size = commandBuffer.size();
00888 int cur_pos = commandCursorPos;
00889
00890 if (com_size >= (linewidth-1))
00891 {
00892 com_size = cur_pos;
00893 }
00894
00895
00896 if (com_size >= (linewidth-1))
00897 {
00898 com += 1 + com_size - (linewidth-1);
00899 cur_pos = linewidth-2;
00900 }
00901
00902 y = lines-(confont->height*2);
00903
00904 surf->PrintCharFixed(confont, ']', confont->width, y);
00905
00906 for (x=0 ; x<(linewidth-2) && com[x]; x++) {
00907 surf->PrintCharFixed(confont, com[x], (x+2)*confont->width, y);
00908
00909 }
00910
00911
00912 if (commandInsert)
00913 surf->Fill32(0xFFFFFFFF, ((cur_pos+2)*confont->width)+1, y, 2, confont->height);
00914 else
00915 surf->Fill32(0xFFFFFFFF, ((cur_pos+2)*confont->width)+1, y+confont->height-2, confont->width, 2);
00916 }
00917
00918
00919 void Console::DrawConsoleNotify (RenderSurface *surf)
00920 {
00921 int x, v;
00922 char *txt;
00923 int i;
00924 int time;
00925
00926 v = 0;
00927 for (i = current-CON_NUM_TIMES+1 ; i<=current ; i++)
00928 {
00929 if (i < 0) continue;
00930 time = con.times[i % CON_NUM_TIMES];
00931 if (time == 0) continue;
00932
00933 time = framenum - time;
00934
00935 if (time > 150)
00936 continue;
00937 txt = text + (i % totallines)*linewidth;
00938
00939 for (x = 0 ; x < con.linewidth ; x++)
00940 surf->PrintCharFixed(confont, txt[x], (x+1)*confont->width, v);
00941
00942 v += confont->height;
00943 }
00944 }
00945
00946