G:/ScriptBasic/source/extensions/dbg/dbg_con.c

Go to the documentation of this file.
00001 /*
00002 FILE: dbg_con.c
00003 HEADER: dbg_comm.h
00004 
00005 --GNU LGPL
00006 This library is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU Lesser General Public
00008 License as published by the Free Software Foundation; either
00009 version 2.1 of the License, or (at your option) any later version.
00010 
00011 This library is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public
00017 License along with this library; if not, write to the Free Software
00018 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019 
00020 This program implements a simple debugger "preprocessor" for ScriptBasic.
00021 
00022 */
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <ctype.h>
00027 
00028 #include "../../conftree.h"
00029 #include "../../report.h"
00030 #include "../../reader.h"
00031 #include "../../basext.h"
00032 #include "../../prepext.h"
00033 
00034 #include "dbg.h"
00035 
00036 /*POD
00037 =H Debugger communication module
00038 
00039 This file implements the functions that are used by the debugger module and,
00040 which communicate with the debugger station. This sample implementation is
00041 the possible simplest example implementation using T<getchar()> to get characters
00042 and T<printf()> to send characters to the user.
00043 
00044 Other implementations should implement the same functions but using more sophisticated
00045 methods, like connecting to a socket where a graphical debugger client application is
00046 accepting connection and wants to communincate with the debugger module.
00047 
00048 CUT*/
00049 
00050 #ifdef WIN32
00051 static HANDLE GetConsoleHandle(){
00052   HANDLE hConsole;
00053 
00054   hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
00055   if( hConsole == NULL ){
00056     AllocConsole();
00057     hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
00058     }
00059   return hConsole;
00060   }
00061 
00062 static void gotoxy(short x, short y){
00063   COORD lp;
00064   HANDLE hConsole;
00065 
00066   lp.X = x; lp.Y = y;
00067   hConsole = GetConsoleHandle();
00068   if( hConsole == NULL )return;
00069   SetConsoleCursorPosition(hConsole,lp);
00070   }
00071 
00072 static int sizeY(){
00073   HANDLE hConsole;
00074   CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
00075 
00076   hConsole = GetConsoleHandle();
00077   if( hConsole == NULL )return 0;
00078   GetConsoleScreenBufferInfo(hConsole,&ConsoleScreenBufferInfo);
00079 
00080   return ConsoleScreenBufferInfo.srWindow.Bottom - ConsoleScreenBufferInfo.srWindow.Top + 1;
00081   }
00082 
00083 static int sizeX(){
00084   HANDLE hConsole;
00085   CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
00086 
00087   hConsole = GetConsoleHandle();
00088   if( hConsole == NULL )return 0;
00089   GetConsoleScreenBufferInfo(hConsole,&ConsoleScreenBufferInfo);
00090 
00091   return ConsoleScreenBufferInfo.srWindow.Right - ConsoleScreenBufferInfo.srWindow.Left + 1;
00092   }
00093 
00094 static void cls(){
00095     COORD coordScreen = { 0, 0 };    /* here's where we'll home the
00096                                         cursor */
00097     BOOL bSuccess;
00098     DWORD cCharsWritten;
00099     CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
00100     DWORD dwConSize;                 /* number of character cells in
00101                                         the current buffer */
00102     HANDLE hConsole;
00103 
00104     hConsole = GetConsoleHandle();
00105     if( hConsole == NULL )return;
00106     /* get the number of character cells in the current buffer */
00107 
00108     bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
00109     dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
00110 
00111     /* fill the entire screen with blanks */
00112 
00113     bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
00114        dwConSize, coordScreen, &cCharsWritten );
00115 
00116     /* get the current text attribute */
00117 
00118     bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
00119 
00120     /* now set the buffer's attributes accordingly */
00121 
00122     bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
00123        dwConSize, coordScreen, &cCharsWritten );
00124 
00125     /* put the cursor at (0, 0) */
00126 
00127     bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
00128     return;
00129  }
00130 
00131 
00132 #endif
00133 
00134 /*POD
00135 =section Init
00136 =H Initiate communication with the debugger station
00137 
00138 This function is called by the debugger when the execution of the program starts.
00139 This function has to set up the debugger environment with the client. Connecting to
00140 the listening socket, clearing screen and so on.
00141 
00142 /*FUNCTION*/
00143 void comm_Init(pDebuggerObject pDO
00144   ){
00145 /*noverbatim
00146 CUT*/
00147 #ifdef WIN32
00148   HANDLE hConsole;
00149 
00150   SetConsoleTitle("ScriptBasic debugger executing");
00151   hConsole = GetConsoleHandle();
00152   if( hConsole )SetConsoleTextAttribute(hConsole,240);
00153   cls();
00154 
00155   gotoxy(1,sizeY()-2);
00156   printf("For help type 'h'\n");
00157 
00158 #else
00159   long i;
00160   printf("ScriptBasic debugger, executing\n");
00161   for( i=0 ; i < pDO->cFileNames ; i++ )
00162     printf("  %s\n",pDO->ppszFileNames[i]);
00163   printf("For help type 'h'");
00164   getche();
00165 #endif
00166   }
00167 
00168 #define SEPARATORLINE   printf("\n-----------------------------------------------------\n");
00169 
00170 /*POD
00171 =section WeAreAt
00172 =H Send prompt to the debugger station
00173 
00174 This function is called by the debugger when it stops before executing
00175 a BASIC line. This function can be used to give some information to the
00176 client, displaying lines around the actual one, values of variables and so on.
00177 
00178 /*FUNCTION*/
00179 void comm_WeAreAt(pDebuggerObject pDO,
00180                   long i
00181   ){
00182 /*noverbatim
00183 CUT*/
00184   int iThis;
00185 
00186 #ifdef WIN32
00187   short y;
00188   HANDLE hConsole;
00189   void comm_List();
00190 
00191   hConsole = GetConsoleHandle();
00192   if( hConsole )SetConsoleTextAttribute(hConsole,240);
00193   iThis = i;
00194   /* the number of lines available for the program code display */
00195   y = sizeY() - pDO->cFileNames - 2 - 3;
00196   /* position the actual line in the middle */
00197   y /= 2;
00198   /* list some lines before */
00199   if( i > y )i -= y; else i = 0;
00200   comm_List(pDO,i,9999999,iThis);
00201 
00202 #else
00203   int j;
00204   iThis = i;
00205   /* list some lines before */
00206   if( i > 2 )i -= 2; else i = 0;
00207 
00208   SEPARATORLINE
00209   for( j = 0 ; j < 5 ; j++ ){
00210     if( i >= pDO->cSourceLines )break;
00211     if( pDO->SourceLines[i].BreakPoint )printf("*"); else printf(" ");
00212     if( i == iThis )printf(">");else printf(" ");
00213     printf("%03d. %s",i+1,pDO->SourceLines[i].line);
00214     i++;
00215     }
00216   SEPARATORLINE
00217 #endif
00218   }
00219 
00220 /*POD
00221 =section List
00222 =H List code lines
00223 
00224 List the source lines from T<lStart> to T<lEnd>.
00225 
00226 The optional T<lThis> may show the caret where the actual execution
00227 context is.
00228 
00229 /*FUNCTION*/
00230 void comm_List(pDebuggerObject pDO,
00231                long lStart,
00232                long lEnd,
00233                long lThis
00234   ){
00235 /*noverbatim
00236 CUT*/
00237   long j;
00238 
00239 #ifdef WIN32
00240   HANDLE hConsole;
00241   short y;
00242 
00243   hConsole = GetConsoleHandle();
00244 
00245   if( lStart < 1 )lStart = 1;
00246   if( lEnd   < 1 )lEnd   = 1;
00247 
00248   SetConsoleTitle("ScriptBasic debugger executing");
00249   cls();
00250   for( j=0 ; j < pDO->cFileNames ; j++ )
00251     printf("  %s\n",pDO->ppszFileNames[j]);
00252 
00253   y = (short) pDO->cFileNames+1;
00254   for( j = lStart-1 ; j < lEnd ; j++ ){
00255     if( j >= pDO->cSourceLines )break;
00256     if( y >= sizeY()-3 )break;
00257     gotoxy(1,y);
00258     y++;
00259     SetConsoleTextAttribute(hConsole,240);
00260     if( pDO->SourceLines[j].BreakPoint ){
00261       SetConsoleTextAttribute(hConsole,252);
00262       printf("*");
00263       }else{
00264       printf(" ");
00265       }
00266     if( j == lThis ){
00267       SetConsoleTextAttribute(hConsole,249);
00268       printf(">");
00269     }else{
00270       printf(" ");
00271     }
00272     printf("%03d. %s",j+1,pDO->SourceLines[j].line);
00273     }
00274 
00275   gotoxy(1,sizeY()-3);
00276   printf("For help type 'h'\n");
00277 
00278 #else
00279 
00280   if( lStart < 1 )lStart = 1;
00281   if( lEnd   < 1 )lEnd   = 1;
00282   printf("\n");
00283   SEPARATORLINE
00284   for( j = lStart-1 ; j < lEnd ; j++ ){
00285     if( j >= pDO->cSourceLines )break;
00286     if( pDO->SourceLines[j].BreakPoint )printf("*"); else printf(" ");
00287     if( j == lThis )printf(">");else printf(" ");
00288     printf("%03d. %s",j+1,pDO->SourceLines[j].line);
00289     }
00290   SEPARATORLINE
00291 #endif
00292   }
00293 
00294 /*POD
00295 =section GetRange
00296 =H get line number range from a string
00297 
00298 This is an auxilliary function, which is used by the debugger.
00299 This simply gets the two numbers from the debugger command and returns
00300 them in the variables pointed by T<plStart> and T<plEnd>.
00301 
00302 For example the command T<B 2-5> removes breakpoints from lines 2,3,4 and 5.
00303 In this case this function will return the numbers 2 and 5.
00304 
00305 If the first number is missing it is returned as 0. If there is first number
00306 but the last one is missing it is returned 999999999.
00307 
00308 If there is first number but it is not followed by '-' then the T<*plEnd> will
00309 be set to zero.
00310 
00311 Finally if there are no numbers on the command line then bot variables are set zero.
00312 /*FUNCTION*/
00313 void GetRange(char *pszBuffer,
00314               long *plStart,
00315               long *plEnd
00316   ){
00317 /*noverbatim
00318 Arguments:
00319 =itemize
00320 =item T<pszBuffer> the debugger command argument string to get the numbers from
00321 =item T<plStart> pointer to the long that will hold the value of the first number
00322 =item T<plEnd> pointer to the long that will hold the value of the second number following the dash character
00323 =noitemize
00324 CUT*/
00325   *plStart = *plEnd = 0;
00326   while( isspace(*pszBuffer) )pszBuffer++;
00327   if( !*pszBuffer )return;
00328   *plStart = atol(pszBuffer);
00329   while( isdigit(*pszBuffer))pszBuffer++;
00330   while( isspace(*pszBuffer) )pszBuffer++;
00331   if( *pszBuffer == '-' ){
00332     pszBuffer++;
00333     *plEnd = 999999999;/* something large, very large */
00334     }
00335   while( isspace(*pszBuffer) )pszBuffer++;
00336   if( !*pszBuffer )return;
00337   *plEnd = atol(pszBuffer);
00338   return;
00339   }
00340 
00341 static void print_help(){
00342 #ifdef WIN32
00343   cls();
00344   SetConsoleTitle("ScriptBasic debugger HELP");
00345 
00346   printf(
00347 "                                                                                  "
00348 "              ScriptBasic Console Debugger Help\n"
00349 "h help\n"
00350 "s step one line, or just press return on the line\n"
00351 "S step one line, do not step into functions or subs\n"
00352 "o step until getting out of the current function\n"
00353 "  (if you stepped into but changed your mind)\n"
00354 "? var  print the value of a variable\n"
00355 "u step one level up in the stack\n"
00356 "d step one level down in the stack (for variable printing)\n"
00357 "D step down in the stack to current execution depth\n"
00358 "G list all global variables\n"
00359 "L list all local variables\n"
00360 "l [n-m] list the source lines\n"
00361 "r [n] run to line n\n"
00362 "R [n] run to line n but do not stop in recursive function call\n"
00363 "b [n] set breakpoint on the line n or the current line\n"
00364 "B [n-m] remove breakpoints from lines\n"
00365 "q quit the program\n"
00366 
00367 "Press any key to return to debugger..."
00368 );
00369 _getch();
00370 #else
00371   printf(
00372 "h help\n"
00373 "s step one line, or just press return on the line\n"
00374 "S step one line, do not step into functions or subs\n"
00375 "o step until getting out of the current function\n"
00376 "  (if you stepped into but changed your mind)\n"
00377 "? var  print the value of a variable\n"
00378 "u step one level up in the stack\n"
00379 "d step one level down in the stack (for variable printing)\n"
00380 "D step down in the stack to current execution depth\n"
00381 "G list all global variables\n"
00382 "L list all local variables\n"
00383 "l [n-m] list the source lines\n"
00384 "r [n] run to line n\n"
00385 "R [n] run to line n but do not stop in recursive function call\n"
00386 "b [n] set breakpoint on the line n or the current line\n"
00387 "B [n-m] remove breakpoints from lines\n"
00388 "q quit the program\n"
00389 );
00390 #endif
00391   }
00392 
00393 /*POD
00394 =section Message
00395 =H Report success of some command
00396 
00397 This function is called when a command that results no output is executed.
00398 The message is an informal message to the client that either tells that the
00399 command was executed successfully or that the command failed and why.
00400 
00401 /*FUNCTION*/
00402 void comm_Message(pDebuggerObject pDO,
00403                   char *pszMessage
00404   ){
00405 /*noverbatim
00406 CUT*/
00407 
00408 #ifdef WIN32
00409 
00410   MessageBoxEx(NULL,pszMessage,"ScriptBasic debugger message",MB_OK|MB_ICONINFORMATION,
00411                             MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US));
00412 
00413 #else
00414   printf("%s\n",pszMessage);
00415 #endif
00416   }
00417 
00418 /*POD
00419 =section GetCommand
00420 =H Prompt the debugger station
00421 
00422 This function should send the prompt to the client and get the client
00423 input. The function should return a single character that represents the
00424 command what the debugger is supposed to do and the possible string argument
00425 in T<pszBuffer>. The available space for the argument is given T<cbBuffer>.
00426 
00427 /*FUNCTION*/
00428 int comm_GetCommand(pDebuggerObject pDO,
00429                     char *pszBuffer,
00430                     long cbBuffer
00431   ){
00432 /*noverbatim
00433 The commands that the debugger accepts: (see help function printout above).
00434 
00435 The function may also implement some printing commands itself, like printing
00436 a help screen.
00437 CUT*/
00438   int i,j;
00439   int ch,cmd;
00440   char pszPrintBuff[1024];
00441   long cbPrintBuff;
00442   pUserFunction_t pUF;
00443   pExecuteObject pEo;
00444   long lStart,lEnd,lThis;
00445 
00446   pEo = pDO->pEo;
00447   while( 1 ){
00448     lThis = GetCurrentDebugLine(pDO);
00449     comm_WeAreAt(pDO,lThis);
00450     printf("#");
00451 
00452     cmd = getchar();
00453     while( isspace(cmd) && cmd != '\n' )cmd = getchar();
00454     if( cmd == '\n' ){
00455       *pszBuffer = (char)0;
00456       return 's';
00457       }
00458     ch = getchar();
00459     while( isspace(ch) && ch != '\n' )ch = getchar();
00460   
00461     for( i=0 ; i < cbBuffer ; i++ ){
00462       if( ch == '\n' )break;
00463       pszBuffer[i] = ch;
00464       ch = getchar();
00465       }
00466     pszBuffer[i] = (char)0;
00467 
00468     switch( cmd ){
00469       case 'l':/*list lines*/
00470         lThis = GetCurrentDebugLine(pDO);
00471 
00472         if( *pszBuffer ){/*if there are arguments*/
00473           GetRange(pszBuffer,&lStart,&lEnd);
00474           comm_List(pDO,lStart,lEnd,lThis);
00475           }else comm_WeAreAt(pDO,lThis);
00476 
00477         continue;
00478       case 'h':  
00479         print_help();
00480         continue;
00481       case '?':
00482         cbPrintBuff = 1204;
00483         i = SPrintVarByName(pDO,pDO->pEo,pszBuffer,pszPrintBuff,&cbPrintBuff);
00484         switch( i ){
00485           case 2:
00486             printf("variable is non-existent\n");
00487             continue;
00488           case 1:
00489             printf("variable is too long to print\n");
00490             continue;
00491           default:
00492             printf("%s\n",pszPrintBuff);
00493           }
00494 #ifdef WIN32
00495         printf("Press any key to continue...");_getch();
00496 #endif
00497       continue;
00498     case 'L': /* list local variables */
00499       if( pDO->StackListPointer == NULL ){
00500         comm_Message(pDO,"program is not local");
00501         continue;
00502         }
00503       pUF = pDO->StackListPointer->pUF;
00504       for( i=0 ; i < pUF->cLocalVariables ; i++ ){
00505         printf("%s=",pUF->ppszLocalVariables[i]);
00506         if( pDO->StackListPointer->LocalVariables ){
00507           j = SPrintVariable(pDO,ARRAYVALUE(pDO->StackListPointer->LocalVariables,i+1),pszPrintBuff,&cbPrintBuff);
00508           switch( j ){
00509             case 2:
00510               printf("variable is non-existent\n");
00511               continue;
00512             case 1:
00513               printf("variable is too long to print\n");
00514               continue;
00515             default:
00516               printf("%s\n",pszPrintBuff);
00517             }
00518           }else{
00519           printf("undef\n");
00520           }
00521         }
00522 #ifdef WIN32
00523         printf("Press any key to continue...");_getch();
00524 #endif
00525       continue;
00526     case 'G':/* list global variables */
00527       for( i=0 ; i < pDO->cGlobalVariables ; i++ ){
00528         printf("%s=",pDO->ppszGlobalVariables[i]);
00529         if( pEo->GlobalVariables ){
00530           j = SPrintVariable(pDO,ARRAYVALUE(pEo->GlobalVariables,i+1),pszPrintBuff,&cbPrintBuff);
00531           switch( j ){
00532             case 2:
00533               printf("variable is non-existent\n");
00534               continue;
00535             case 1:
00536               printf("variable is too long to print\n");
00537               continue;
00538             default:
00539               printf("%s\n",pszPrintBuff);
00540             }
00541           }else
00542           printf("undef\n");
00543         }
00544 #ifdef WIN32
00545         printf("Press any key to continue...");_getch();
00546 #endif
00547       continue;
00548       }
00549 
00550     break;
00551     }
00552   return cmd;
00553   }

Generated on Sun Mar 12 23:56:30 2006 for ScriptBasic by  doxygen 1.4.6-NO