home *** CD-ROM | disk | FTP | other *** search
/ Enter 2005 March / ENTER.ISO / files / fwp-0.0.6-win32-installer.exe / Console.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-12-06  |  14.9 KB  |  640 lines

  1. #include "Console.h"
  2. #include "CVar.h"
  3. #include "CCmd.h"
  4. #include "CAlias.h"
  5. #include "Tokenizer.h"
  6.  
  7. #include <stdarg.h>
  8.  
  9. #include "log.h"
  10.  
  11. Console* console = NULL;
  12.  
  13.  
  14.  
  15. /*
  16.     Creates a new (empty) console
  17. */
  18. Console::Console(){
  19.     int i;
  20.  
  21.     for(i=0;i<CON_MAX_CVARS;i++)
  22.         cVars[i]=NULL;
  23.     for(i=0;i<CON_MAX_CCMDS;i++)
  24.         cCmds[i]=NULL;
  25.     for(i=0;i<CON_MAX_ALIASES;i++)
  26.         aliases[i]=NULL;
  27.     for(i=0;i<CON_MAX_LINES;i++)
  28.         lines[i]=NULL;
  29. //    for(i=0;i<CON_MAX_HISTORY_LINES;i++)
  30. //        historyLines[i]=NULL;
  31.  
  32.     accessFlags=CON_FLAG_NONE_SET;
  33.  
  34.     logFile=NULL;
  35.     logOutput=false;
  36. }
  37.  
  38. Console::~Console(){
  39.     int i;
  40.  
  41.     for(i=0;i<CON_MAX_LINES;i++){
  42.         if(lines[i]!=NULL){
  43.             delete[] lines[i];
  44.             lines[i]=NULL;
  45.         }
  46.     }
  47.  
  48. //    for(i=0;i<CON_MAX_HISTORY_LINES;i++){
  49. //        if(historyLines[i]!=NULL){
  50. //            delete[] historyLines[i];
  51. //            historyLines[i]=NULL;
  52. //        }
  53. //    }
  54.  
  55.     for(i=0;i<CON_MAX_CCMDS;i++){
  56.         if(cCmds[i]!=NULL){
  57.             cCmds[i]->setConsole(NULL);
  58.             cCmds[i]=NULL;
  59.         }
  60.     }
  61.  
  62.     if(logOutput)
  63.         endLog();
  64.  
  65.     // THINKABOUTME: cvars l÷schen?? Und aliases???
  66. }
  67.  
  68. /*
  69.     The console recieves input through this function.
  70.     The input string is printed in the console window and then parsed.
  71. */
  72. void Console::input(const char* inputStr){
  73.     print("> %s\n", inputStr);
  74. //    appendHistoryLine(inputStr);
  75.     parse(inputStr);
  76. }
  77.  
  78. /*
  79.     This function prints a printf-format-string in the console window
  80. */
  81. void Console::print(const char* formatString,...){
  82.     char buff[CON_MAX_STRING_LENGTH];
  83.     va_list ap;
  84.     int count;
  85.  
  86.     va_start (ap, formatString);
  87. #ifdef WIN32
  88.     count = _vsnprintf(buff, CON_MAX_STRING_LENGTH, formatString, ap);
  89. #else
  90.     count = vsnprintf(buff, CON_MAX_STRING_LENGTH, formatString, ap);
  91. #endif
  92.     va_end(ap);
  93.  
  94.     if(count == -1){
  95.         print("\n## ERROR: (in console.print): formatString too long.\n\n");
  96.         return;
  97.     }
  98.     appendLine(buff);
  99.  
  100.     if(logOutput && logFile!=NULL){
  101.         fprintf(logFile, buff);
  102.     }
  103. }
  104.  
  105. /*
  106.     adds a line to the consoles output
  107. */
  108. void Console::appendLine(const char *line){
  109.     int i;
  110.  
  111.     if(lines[CON_MAX_LINES-1]!=NULL)        // delete last line
  112.         delete[] lines[CON_MAX_LINES-1];    
  113.  
  114.     for(i=CON_MAX_LINES-1; i>0; i--){    // move all one position up
  115.         lines[i]=lines[i-1];
  116.     }
  117.  
  118. //    int t=strlen(line);
  119.     lines[0]=new char[strlen(line)+1];
  120.     lines[0]=strncpy(lines[0], line, strlen(line)+1);
  121. }
  122.  
  123.  
  124. /*
  125.     adds a line to the consoles input history
  126. */
  127. /*
  128. void Console::appendHistoryLine(const char *line){
  129.     int i;
  130.  
  131.     if(lines[CON_MAX_HISTORY_LINES-1]!=NULL)        // delete last line
  132.         delete[] historyLines[CON_MAX_HISTORY_LINES-1];    
  133.  
  134.     for(i=CON_MAX_HISTORY_LINES-1; i>0; i--){    // move all one position up
  135.         historyLines[i]=historyLines[i-1];
  136.     }
  137.  
  138. //    int t=strlen(line);
  139.     historyLines[0]=new char[strlen(line)+1];
  140.     historyLines[0]=strncpy(historyLines[0], line, strlen(line)+1);
  141. }
  142. */
  143.  
  144. /*
  145.     This function parses a string and executes the corresponding commands.
  146.     This is the heart of the conosle.
  147.     It return true if ALL commands in parseStr were executed without failure and false if an error occured.
  148. */
  149. bool Console::parse(const char* parseStr){
  150.     if(parseStr==NULL)
  151.         return false;
  152.  
  153. //    printf("console::parse(): %s\n", parseStr);
  154.  
  155.     if(*parseStr=='\0')
  156.         return true;
  157.         
  158.     int i;
  159.  
  160.     char* p=(char*)parseStr;
  161.     char* start=NULL;
  162.     char* tokens[CON_MAX_STRING_LENGTH];    // can't have more tokens than chars in the string...
  163.     int numTokens=0;
  164.  
  165.     for(i=0;i<CON_MAX_STRING_LENGTH;i++){
  166.         tokens[i]=NULL;
  167.     }
  168.  
  169.     while(*p!='\0' && *p!=';' && *p!='\n' && *p!='\r'){    // THINKABOUTME: how to treat '\n' and '\r'?
  170.         if(numTokens>=CON_MAX_STRING_LENGTH){
  171.             print("by far too many tokens!!");
  172.             return false;
  173.         }
  174.         if(*p==' ' || *p=='\t'){
  175.             if(start!=NULL){    // end the token
  176.                 tokens[numTokens]=newString(start, p-start);
  177.                 numTokens++;
  178.                 start=NULL;
  179.             }
  180.             p++;
  181.         }else if(*p=='\"'){
  182.             if(start!=NULL){    // end the token
  183.                 tokens[numTokens]=newString(start, p-start);
  184.                 numTokens++;
  185.                 start=NULL;
  186.             }
  187.             p++;    // skip the '\"' itself
  188.             start=p;
  189.             while(*p!='\"' && *p!='\0'){
  190.                 p++;
  191.             }
  192.             if(*p=='\0'){
  193.                 print("error...");
  194.                 return false;
  195.             }
  196.             if(*p=='\"'){    // this is certain at this point...
  197.                 tokens[numTokens]=newString(start, p-start);
  198.                 numTokens++;
  199.                 start=NULL;
  200.             }
  201.             p++;    // skip the closing '\"'
  202.         }else if(*p=='{'){
  203.             if(start!=NULL){    // end the token
  204.                 tokens[numTokens]=newString(start, p-start);
  205.                 numTokens++;
  206.                 start=NULL;
  207.             }
  208.             p++;    // skip the '{' itself
  209.             start=p;
  210.             int numBracketsOpened=1;
  211.             while(numBracketsOpened!=0 && *p!='\0'){
  212.                 if(*p=='{')    // FIXME: do not count brackets in '\"'
  213.                     numBracketsOpened++;
  214.                 if(*p=='}')
  215.                     numBracketsOpened--;
  216.                 p++;
  217.             }
  218.             if(*p=='\0' && numBracketsOpened!=0){
  219.                 print("error...");
  220.                 return false;
  221.             }
  222.             p--; // substract the last p++ of the while-loop
  223.             if(*p=='}'){    // this is certain at this point...
  224.                 tokens[numTokens]=newString(start, p-start);
  225.                 numTokens++;
  226.                 start=NULL;
  227.             }
  228.             p++;    // skip the closing '}'
  229.         }else if(*p=='}'){
  230.             // THINKABOUTME: fehler ausgeben oder nicht?
  231.         }else{    // any other character
  232.             if(start==NULL)        // start new token if not already one in progress
  233.                 start=p;
  234.             p++;
  235.         }
  236.     } //while
  237.  
  238.     if(start!=NULL && numTokens<CON_MAX_STRING_LENGTH-1){
  239.             tokens[numTokens]=newString(start, p-start);
  240.             numTokens++;
  241.             start=NULL;
  242.     }
  243.  
  244. /*
  245.     printf("tokens: %i\n", numTokens);
  246.     for(i=0;i<numTokens;i++){
  247.         printf("%s\n",tokens[i]);
  248.     }
  249. */
  250.  
  251.     bool retVal=true;
  252.     char val[CON_MAX_STRING_LENGTH];
  253.     char varVal[CON_MAX_STRING_LENGTH];
  254.  
  255.     CCmd* cCmd=NULL;
  256.     CVar* cVar=NULL;
  257.     CAlias* alias=NULL;
  258.  
  259.  
  260.     if(numTokens==0)
  261.         return true;
  262.  
  263. aliasFound:    // FIXME: ordentlich machen!!
  264.     cCmd=getCCmd(tokens[0]);
  265.     if(cCmd!=NULL){
  266.         if( true /*hasAccessToCCmd(cCmd, CON_FLAG_EXECUTE)*/){
  267.             if(!cCmd->exec(numTokens-1, &tokens[1]))
  268.                 retVal=false;    // we return only false on parse errors
  269.         }else{
  270.             print("'%s': exec access denied\n", cCmd->name);
  271.             retVal=false;
  272.         }
  273.     }else{        // cCmd is NULL -> search for a cVar
  274.         cVar=getCVar(tokens[0]);
  275.         if(cVar!=NULL){
  276.             if(numTokens==1){
  277.                 if(true /*hasAccessToCVar(cVar, CON_FLAG_READ)*/){
  278.                     cVar->getValStr(val);
  279.                     cVar->getVarValStr(varVal);
  280.                     if(streq(val, varVal))
  281.                         print("value of '%s': %s\n", cVar->name, val);
  282.                     else
  283.                         print("value of '%s': %s (internal value: %s)\n", cVar->name, val, varVal);
  284.                 }else{
  285.                     print("'%s': read access denied\n", cVar->name);
  286.                     retVal=false;
  287.                 }
  288.             }else if(numTokens==2){
  289.                 if( (cVar->flags & CON_FLAG_READ_ONLY) != CON_FLAG_READ_ONLY){
  290.                     if(cVar->valStrIsValid(tokens[1])){
  291.                         cVar->setValStr(tokens[1]);
  292.                         print("'%s' set to %s %s\n", cVar->name, cVar->getValStr(val), cVar->changeStr);
  293.                     }else{
  294.                         print("'%s' is not a valid value for '%s'\n", tokens[1], cVar->name);
  295.                         retVal=false;
  296.                     }
  297.                 }else{
  298.                     print("'%s' is read-only.\n", cVar->name);
  299.                     retVal=false;
  300.                 }
  301.             }else{
  302.                 print("Syntax error: '%s' (to many tokens: %i)\n", tokens[0], numTokens);
  303.                 retVal=false;
  304.             }
  305.         }else{    // no cvar found -> search for alias
  306.             alias=getAlias(tokens[0]);
  307.             if(alias!=NULL){
  308.                 delete[] tokens[0];
  309.                 tokens[0]=newString(alias->string);
  310.                 goto aliasFound;
  311.             }else{
  312.                 print("Unknown command or variable: '%s'\n", tokens[0]);
  313.                 retVal=false;
  314.             }
  315.         }
  316.     }// else (CCmd==NULL)
  317.  
  318.     for(i=0;i<numTokens;i++){
  319.         delete[] tokens[i];
  320.     }
  321.  
  322.     if(*p==';')
  323.         return (parse(p+1) && retVal);    // return only true if ALL ccmds are executed without errors
  324.     else
  325.         return retVal;
  326.  
  327. }
  328.  
  329. /*
  330.     clears all output lines
  331. */
  332. void Console::clear(){
  333.     int i;
  334.  
  335.     for(i=0;i<CON_MAX_LINES;i++){
  336.         if(lines[i]!=NULL){
  337.             delete[] lines[i];
  338.             lines[i]=NULL;
  339.         }
  340.     }
  341. }
  342.  
  343.  
  344. /*
  345.     clears input history
  346. */
  347. /*
  348. void Console::clearHistory(){
  349.     int i;
  350.  
  351.     for(i=0;i<CON_MAX_HISTORY_LINES;i++){
  352.         if(historyLines[i]!=NULL){
  353.             delete[] historyLines[i];
  354.             historyLines[i]=NULL;
  355.         }
  356.     }
  357. }
  358. */
  359.  
  360. /*
  361.     registers a new cvar, so that the console can work on it
  362. */
  363. bool Console::registerCVar(CVar* cVar){
  364.     int i;
  365.  
  366.     for(i=0;i<CON_MAX_CVARS;i++){
  367.         if(cVars[i]!=NULL && streq(cVars[i]->name, cVar->name)){
  368.  
  369.             print("\n##ERROR: couldn't register cvar '%s'. Another cvar with that name already exists!\n\n", cVar->name);
  370.             return false;    // cvar with name already exists
  371.         }
  372.     }
  373.  
  374.     for(i=0;i<CON_MAX_CVARS;i++){
  375.         if(cVars[i]==NULL){
  376.             cVars[i]=cVar;    // register the cvar
  377.             print("cvar '%s' successfully registered.\n", cVar->name);
  378.             return true;
  379.         }
  380.     }
  381.  
  382.     print("\n##ERROR: couldn't register cvar '%s'. CON_MAX_CVARS reached\n\n", cVar->name);
  383.     return false;        // there was no free slot
  384. }
  385.  
  386. /*
  387.  
  388.     unregisters a cvar (but does NOT delete it)
  389. */
  390. bool Console::unregisterCVar(CVar* cVar){
  391.     int i;
  392.  
  393.     for(i=0;i<CON_MAX_CVARS;i++){
  394.         if(cVars[i]==cVar){
  395.             cVars[i]=NULL;    // THIS DOES NOT DELETE THE CVAR!!!
  396.             print("cvar '%s' successfully unregistered.\n", cVar->name);
  397.             return true;
  398.         }
  399.     }
  400.  
  401.     print("\n##ERROR: couldn't unregister cvar '%s'.\n\n", cVar->name);
  402.     return false;        // no cvar with name 'name' found
  403. }
  404.  
  405. /*
  406.     THIS really DELETES a cvar
  407. */
  408. bool Console::deleteCVar(CVar* cVar){
  409.     int i;
  410.  
  411.  
  412.     for(i=0;i<CON_MAX_CVARS;i++){
  413.         if(cVars[i]==cVar && cVars[i]!=NULL){
  414.             delete cVars[i];        // THINKABOUTME: wirklich l÷schen???
  415.             cVars[i]=NULL;
  416.             print("cvar '%s' successfully deleted.\n", cVar->name);
  417.             return true;    // delete cvar
  418.         }
  419.     }
  420.  
  421.     print("\n##ERROR: couldn't delete cvar '%s'.\n\n", cVar->name);
  422.     return false;        // no cvar with name 'name' found
  423. }
  424.  
  425.  
  426. /*
  427.     returns a pointer to the cvar called 'name'
  428. */
  429. CVar* Console::getCVar(const char* name){
  430.     int i;
  431.  
  432.     for(i=0;i<CON_MAX_CVARS;i++)
  433.         if(cVars[i]!=NULL && streq(cVars[i]->name, name))
  434.             return cVars[i];
  435.  
  436.     return NULL;    // no cvar with name 'name' found
  437. }
  438.  
  439.  
  440. /*
  441.     Same as for cvars
  442. */
  443. bool Console::registerCCmd(CCmd* cCmd){
  444.     int i;
  445.  
  446.     for(i=0;i<CON_MAX_CCMDS;i++){
  447.         if(cCmds[i]!=NULL && streq(cCmds[i]->name, cCmd->name)){
  448.             print("\n##ERROR: couldn't register ccmd '%s'. Another ccmd with that name already exists!\n\n", cCmd->name);
  449.             return false;    // cvar with name already exists
  450.         }
  451.     }
  452.  
  453.     for(i=0;i<CON_MAX_CCMDS;i++){
  454.         if(cCmds[i]==NULL){
  455.             cCmds[i]=cCmd;    // register the ccmd
  456.             cCmds[i]->setConsole(this);
  457.             print("ccmd '%s' successfully registered.\n", cCmd->name);
  458.             return true;
  459.         }
  460.     }
  461.  
  462.     print("\n##ERROR: couldn't register ccmd '%s'. CON_MAX_CCMDS reached\n\n", cCmd->name);
  463.     return false;        // there was no free slot
  464. }
  465.  
  466. bool Console::unregisterCCmd(CCmd* cCmd){
  467.     int i;
  468.  
  469.     for(i=0;i<CON_MAX_CCMDS;i++){
  470.         if(cCmds[i]!=NULL && cCmds[i]==cCmd){
  471.             cCmds[i]->setConsole(NULL);
  472.             cCmds[i]=NULL;
  473.             print("ccmd '%s' successfully unregistered.\n", cCmd->name);
  474.             return true;
  475.         }
  476.     }
  477.     print("\n##ERROR: couldn't unregister ccmd '%s'. No ccmd with that name found!\n\n", cCmd->name);
  478.     return false;        // no ccmd with name 'name' found
  479. }
  480.  
  481. bool Console::deleteCCmd(CCmd* cCmd){
  482.     int i;
  483.  
  484.     for(i=0;i<CON_MAX_CCMDS;i++){
  485.         if(cCmds[i]!=NULL && cCmds[i]==cCmd){
  486.             delete cCmds[i];        // THINKABOUTME: wirklich l÷schen???
  487.             cCmds[i]=NULL;
  488.             print("ccmd '%s' successfully deleted.\n", cCmd->name);
  489.             return true;
  490.         }
  491.     }
  492.  
  493.     print("\n##ERROR: couldn't delete ccmd '%s'. No ccmd with that name found!\n\n", cCmd->name);
  494.     return false;        // no cvar with name 'name' found
  495. }
  496.  
  497. CCmd* Console::getCCmd(const char* name){
  498.     int i;
  499.  
  500.     for(i=0;i<CON_MAX_CCMDS;i++)
  501.         if(cCmds[i]!=NULL && streq(cCmds[i]->name,name))
  502.             return cCmds[i];
  503.  
  504.     return NULL;    // no ccmd with name 'name' found
  505. }
  506.  
  507. /*
  508.     returns true if the console has 'desiredAccess' to 'cVar' (e.g. read, write, ...)
  509. */
  510. bool Console::hasAccessToCVar(CVar* cVar, unsigned int desiredAccess){
  511.         return true;
  512. }
  513.  
  514. /*
  515.     returns true if the console has 'desiredAccess' to 'cCmd' (e.g. execute, ...)
  516. */
  517. bool Console::hasAccessToCCmd(CCmd* cCmd, unsigned int desiredAccess){
  518.     return true;//(accessFlags & cCmd->flags) == desiredAccess;
  519. }
  520.  
  521.  
  522.  
  523. /*
  524.     Same as for cvars
  525. */
  526. bool Console::registerAlias(CAlias* alias){
  527.     int i;
  528.  
  529.     CCmd* test=getCCmd(alias->name);
  530.     if(test!=NULL){
  531.         printf("A ccmd with name '%s' already exists! Overwriting ccmds with aliases is forbidden.\n", alias->name);
  532.         return false;
  533.     }
  534.     CVar* test2=getCVar(alias->name);
  535.     if(test2!=NULL){
  536.         printf("A cvar with name '%s' already exists! Overwriting cvars with aliases is forbidden.\n", alias->name);
  537.         return false;
  538.     }
  539.     if(streq(alias->name, alias->string)){
  540.         printf("alias '%s': name and string are identical. This is forbidden.\n", alias->name);
  541.         return false;
  542.     }
  543.  
  544.     for(i=0;i<CON_MAX_ALIASES;i++){
  545.         if(aliases[i]!=NULL && streq(aliases[i]->name, alias->name)){
  546.             print("\n##WARNING: Another alias with name '%s' already exists! Overwriting it.\n\n", alias->name);
  547.             delete aliases[i];    // THINKABOUTME
  548.             aliases[i]=alias;
  549.             return true;    // alias with name already exists
  550.         }
  551.     }
  552.  
  553.     for(i=0;i<CON_MAX_ALIASES;i++){
  554.         if(aliases[i]==NULL){
  555.             aliases[i]=alias;    // register the alias
  556.             //aliass[i]->setConsole(this);
  557.             print("alias '%s' successfully registered.\n", alias->name);
  558.             return true;
  559.         }
  560.     }
  561.  
  562.     print("\n##ERROR: couldn't register alias '%s'. CON_MAX_ALIASES reached\n\n", alias->name);
  563.     return false;        // there was no free slot
  564. }
  565.  
  566. bool Console::unregisterAlias(CAlias* alias){
  567.     int i;
  568.  
  569.     for(i=0;i<CON_MAX_ALIASES;i++){
  570.         if(aliases[i]!=NULL && aliases[i]==alias){
  571.             //aliass[i]->setConsole(NULL);
  572.             aliases[i]=NULL;    // THIS DOES NOT DELETE THE Alias!!!
  573.             print("alias '%s' successfully unregistered.\n", alias->name);
  574.             return true;
  575.         }
  576.     }
  577.     print("\n##ERROR: couldn't unregister alias '%s'. No alias with that name found!\n\n", alias->name);
  578.     return false;        // no alias with name 'name' found
  579. }
  580.  
  581. bool Console::deleteAlias(CAlias* alias){
  582.     int i;
  583.  
  584.     for(i=0;i<CON_MAX_ALIASES;i++){
  585.         if(aliases[i]!=NULL && aliases[i]==alias){
  586.             delete aliases[i];        // THINKABOUTME: wirklich l÷schen???
  587.             aliases[i]=NULL;
  588.             print("alias '%s' successfully deleted.\n", alias->name);
  589.             return true;
  590.         }
  591.     }
  592.  
  593.     print("\n##ERROR: couldn't delete alias '%s'. No alias with that name found!\n\n", alias->name);
  594.     return false;        // no alias with name 'name' found
  595. }
  596.  
  597. CAlias* Console::getAlias(const char* name){
  598.     int i;
  599.  
  600.     for(i=0;i<CON_MAX_ALIASES;i++)
  601.         if(aliases[i]!=NULL && streq(aliases[i]->name,name))
  602.             return aliases[i];
  603.  
  604.     return NULL;    // no CAlias with name 'name' found
  605. }
  606.  
  607.  
  608.  
  609.  
  610.  
  611. void Console::startLog(const char* filename){
  612.     if(logOutput){
  613.         print("There is already a session in progress. I am closing it first...\n");
  614.         endLog();
  615.     }
  616.  
  617.     print("logging console output to file '%s'...\n", filename);
  618.  
  619.     logFile=fopen(filename, "wt");
  620.     if(logFile==NULL){
  621.         print("Couln't open file '%s'...\n");
  622.  
  623.         return;
  624.     }
  625.  
  626.     fprintf(logFile, "*** starting console log ***\n");
  627.  
  628.     logOutput=true;
  629. }
  630. void Console::endLog(){
  631.     if(logOutput){
  632.         print("closing console log...\n");
  633.         fclose(logFile);
  634.         logFile=NULL;
  635.         logOutput=false;
  636.     }else{
  637.         print("no log in progress.\n");
  638.     }
  639. }
  640.