1) Remove the empty root node from PHPVariable list.
[phpeclipse.git] / net.sourceforge.phpeclipse.debug.core / src / net / sourceforge / phpdt / internal / debug / core / PHPDBGInterface.java
1 /**********************************************************************
2 Copyright (c) 2000, 2002 IBM Corp. and others.
3 All rights reserved. This program and the accompanying materials
4 are made available under the terms of the Common Public License v1.0
5 which accompanies this distribution, and is available at
6 http://www.eclipse.org/legal/cpl-v10.html
7
8 Contributors:
9         Vicente Fernando - www.alfersoft.com.ar - Initial implementation
10         Christian Perkonig - remote debug
11 **********************************************************************/
12 package net.sourceforge.phpdt.internal.debug.core;
13
14 import java.io.BufferedReader;
15 import java.io.IOException;
16 import java.io.OutputStream;
17 import java.util.Vector;
18 import java.util.Collections;
19
20 import net.sourceforge.phpdt.internal.debug.core.model.PHPDBGEvalString;
21 import net.sourceforge.phpdt.internal.debug.core.model.PHPStackFrame;
22 import net.sourceforge.phpdt.internal.debug.core.model.PHPVariable;
23 import net.sourceforge.phpdt.internal.debug.core.model.PHPValue;
24
25 import org.eclipse.core.runtime.IStatus;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.debug.core.DebugException;
28
29 /**
30  * The interface object are created by the proxy
31  *
32  */
33 public class PHPDBGInterface {
34
35         public boolean                  sessionEnded = false;
36         public int                              sessType         = -1;
37         public int                              BPUnderHit       = 0;
38         public String                   sessID           = new String ();
39
40         private int[]                   LastBPRead   = new int[10];
41         private Vector                  DBGBPList    = new Vector ();
42         private Vector          DBGVarList   = new Vector ();
43         private PHPStackFrame[] DBGStackList;
44         private Vector                  DBGMods          = new Vector ();                       // The module names and their numbers
45         private Vector          stackListOld = new Vector ();
46         private BufferedReader  in;
47         private OutputStream    os;                                                                             // The stream which goes to DBG
48         private boolean                 shouldStop       = false;
49         private String                  evalRet          = new String ("");
50         private String                  serGlobals       = new String ("");
51         private int                     rawCounter       = 1000;                                        // An rawData frame ID counter
52         private PHPDBGProxy     proxy            = null;
53         private int                     lastCmd          = -1;
54         private int                     sid                      = 0;
55         private boolean                 stopOnError      = false;
56         private char[]                  lastCommand      = new char[4];
57
58         /**
59          * @param in    The input stream (communication from DBG).
60          * @param os    The output stream (communication to DBG).
61          * @param proxy The proxy to which this interface belongs.
62          */
63         public PHPDBGInterface (BufferedReader in, OutputStream os, PHPDBGProxy proxy) {
64                 DBGBPList.clear ();
65
66                 this.in         = in;
67                 this.os         = os;
68                 this.proxy      = proxy;
69         }
70
71         /**
72          *
73          * @param mod_name The module (source file) to which we add the breakpoint.
74          * @param line     The line where the breakpoint is set.
75          * @return         Breakpoint ID ???.
76          */
77         public int addBreakpoint (String mod_name, int line) throws IOException {
78                 return setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_ENABLED + PHPDBGBase.BPS_UNRESOLVED, 0, 0, 0, 0, 0);
79         }
80
81         /**
82          *
83          * @param mod_name The module (source file) to which we add the breakpoint.
84          * @param line     The line where the breakpoint is set.
85          * @param bpNo     The breakpoint ID ???.
86          */
87         public void removeBreakpoint (String mod_name, int line, int bpNo) throws IOException {
88                 setBreakpoint (mod_name, "", line, PHPDBGBase.BPS_DISABLED, 0, 0, 0, bpNo, 0);
89         }
90
91         /**
92          * Is this method used anywhere?
93          *
94          */
95         public void requestDBGVersion () throws IOException {
96                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
97                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
98
99                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
100                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_VER);         // We want the version of DBG
101
102                 DBGPacket.addFrame (DBGFrame);                              // Add the 'what we want' to the DBG packet
103
104                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
105                         return;                                                 //  No
106                 }
107
108                 DBGPacket.sendPacket (os);                                                                      // Send the request to DBG
109         }
110
111         /**
112          * Called by the proxy
113          *
114          */
115         public void getSourceTree () throws IOException {
116                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
117                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
118
119                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
120                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_SRC_TREE);        // We want a source tree from DBG
121
122                 DBGPacket.addFrame (DBGFrame);                              // Add the 'what we want' to the DBG packet
123
124                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
125                         return;                                                                                                 //  No
126                 }
127
128                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
129
130                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
131                 flushAllPackets ();                                                                             // Read and process the response from DBG
132         }
133
134         /**
135          * Is this method called from anywhere?
136          *
137          * @param modName The modul (filename).
138          */
139         public void addDBGModName (String modName) throws IOException {
140                 PHPDBGPacket DBGPacket;                                     // A DBG message packet
141                 PHPDBGFrame  DBGFrame;                                      // A frame within a DBG packet
142
143                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     // A request for DBG
144                 DBGFrame  = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);     // We want Module name from DBG
145
146                 rawCounter++;                                               // Increment the rawData ID counter
147                 DBGFrame.addInt (rawCounter);                                                           // FRAME_RAWDATA ID
148                 DBGFrame.addInt (modName.length () + 1);                                        // The length of rawdata string (incl. null char termination)
149                 DBGFrame.addString (modName);                                                           // The file name (module name)
150                 DBGFrame.addChar ('\0');                                                                        // Add the C-String null termination
151
152                 DBGPacket.addFrame (DBGFrame);
153
154                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
155                         return;                                                                                                 //  No
156                 }
157
158                 DBGPacket.sendPacket (os);
159         }
160
161         /**
162          * This method is called for adding or removing breakpoints.
163          *
164          * @param mod_name      The module name (file name).
165          * @param condition     Info about the condition when to break (not used at the moment).
166          * @param line          The breakpoints line.
167          * @param state         Info whether this breakpoint has to be dis- or enabled.
168          * @param istep         Always 0.
169          * @param hitcount      Always 0.
170          * @param skiphits      Always 0.
171          * @param bpno          The breakpoint ID.
172          * @param isunderhit    ???
173          * @return
174          */
175         private int setBreakpoint (String mod_name, String condition, int line, int state, int istemp, int hitcount, int skiphits, int bpno, int isunderhit) throws IOException {
176                 PHPDBGPacket    DBGPacket;
177                 PHPDBGFrame     DBGFrame1;
178                 PHPDBGFrame     DBGFrame2;
179                 int                     modNo;
180
181                 DBGPacket       = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);
182                 DBGFrame1       = new PHPDBGFrame (PHPDBGBase.FRAME_BPS);
183                 DBGFrame2       = new PHPDBGFrame (PHPDBGBase.FRAME_RAWDATA);
184
185                 modNo           = getModByName (mod_name);                                              // Get the module ID by name
186
187                 if (modNo >= 0) {                                           // Did we find a module ID for the module name?
188                         DBGFrame1.addInt (modNo);                                                               // Add the module ID to frame 1
189                 } else {
190                         DBGFrame1.addInt (0);                                                                   // mod number (0 use file name)
191                 }
192
193                 DBGFrame1.addInt (line);                                                                        // line number
194
195                 if (modNo >= 0) {                                           // Did we find a module ID for the module name?
196                         DBGFrame1.addInt (0);                                                                   // use mod number
197                 } else {
198                         rawCounter++;
199                         DBGFrame1.addInt (rawCounter);                                                  // ID of FRAME_RAWDATA to send file name
200                 }
201
202                 DBGFrame1.addInt (state);                                       // state BPS_*
203                 DBGFrame1.addInt (istemp);                                      // istep
204                 DBGFrame1.addInt (hitcount);                                // hit count
205                 DBGFrame1.addInt (skiphits);                                // skip hits
206                 DBGFrame1.addInt (0);                                           // ID of condition
207                 DBGFrame1.addInt (bpno);                                            // breakpoint number
208                 DBGFrame1.addInt (isunderhit);                                  // is under hit
209
210                 if (modNo < 0) {                                            // Did we find a module ID for the module name?
211                         DBGFrame2.addInt (rawCounter);                                      // FRAME_RAWDATA ID
212                         DBGFrame2.addInt (mod_name.length() + 1);                   // length of rawdata (+ null char)
213                         DBGFrame2.addString (mod_name);                                     // file name
214                         DBGFrame2.addChar ('\0');                                                   // null char
215
216                         DBGPacket.addFrame (DBGFrame2);                         // First add file name data
217                 }
218
219                 DBGPacket.addFrame (DBGFrame1);                                                         // Second add command data
220
221                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
222                         return 0;                                               //  No
223                 }
224
225                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
226
227                 clearLastBP ();
228
229                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
230                 flushAllPackets ();                                         // Read and process the response from DBG
231
232                 return LastBPRead[8];                                                                           // Return what ???
233         }
234
235         /**
236          *
237          */
238         private void clearLastBP () {
239                 int i;
240
241                 for (i = 0; i < LastBPRead.length; i++) {
242                         LastBPRead[i] = 0;
243                 }
244         }
245
246         /**
247          *
248          */
249         private void copyToLastBP (int[] BPBody) {
250                 int i;
251
252                 for (i = 0; i < LastBPRead.length; i++) {
253                         LastBPRead[i] = BPBody[i];
254                 }
255         }
256
257         /**
258          *
259          */
260         public void continueExecution () throws IOException {
261                 PHPDBGPacket DBGPacket;
262
263                 BPUnderHit = 0;
264                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_CONTINUE);
265
266                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
267                         return;                                                 //  No
268                 }
269
270                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
271
272                 lastCommand = PHPDBGBase.DBGA_CONTINUE;                     // Store the info about the command we sent
273         }
274
275         /**
276          *
277          */
278         public void pauseExecution () throws IOException {
279                 PHPDBGPacket DBGPacket;
280
281                 DBGPacket = new PHPDBGPacket (PHPDBGBase.IntToChar4 (PHPDBGBase.DBGC_PAUSE));
282
283                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
284                          return;                                                //  No
285                 }
286
287                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
288         }
289
290         /**
291          *
292          */
293         private int getBPUnderHit () {
294                 int i;
295                 int BPUnder             = 0;
296                 int[] dbg_bpl_body      = new int[10];
297
298                 for (i = 0; i < DBGBPList.size (); i++) {                               // look for bp under hit
299                         dbg_bpl_body = (int[]) DBGBPList.get (i);
300
301                         if (dbg_bpl_body[9] == 1) {
302                                 BPUnder = dbg_bpl_body[8];
303                         }
304                 }
305
306                 return BPUnder;
307         }
308
309         public int getLastCmd()
310         {
311                 return lastCmd;
312         }
313
314         public int getSID()
315         {
316           return sid;
317         }
318
319         public void setLastCmd (int cmd)
320         {
321                 lastCmd = cmd;
322         }
323
324         /**
325          *
326          */
327         public void stepInto () throws IOException {
328                 PHPDBGPacket DBGPacket;
329
330                 BPUnderHit = 0;
331                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPINTO);
332
333                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
334                         return;                                                 //  No
335                 }
336
337                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
338
339                 lastCommand = PHPDBGBase.DBGA_STEPINTO;                                         // Store the info about the command we sent
340         }
341
342         /**
343          *
344          */
345         public void stepOver () throws IOException {
346                 PHPDBGPacket DBGPacket;
347
348                 BPUnderHit = 0;
349                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOVER);
350
351                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
352                         return;                                                 //  No
353                 }
354
355                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
356
357                 lastCommand = PHPDBGBase.DBGA_STEPOVER;                     // Store the info about the command we sent
358         }
359
360         /**
361          *
362          */
363         public void stepOut () throws IOException {
364                 PHPDBGPacket DBGPacket;
365
366                 BPUnderHit = 0;
367                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STEPOUT);
368
369                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
370                         return;                                                 //  No
371                 }
372
373                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
374
375                 lastCommand = PHPDBGBase.DBGA_STEPOUT;                      // Store the info about the command we sent
376         }
377
378         /**
379          *
380          */
381         public void stopExecution () throws IOException {
382                 PHPDBGPacket DBGPacket;
383
384                 BPUnderHit = 0;
385                 DBGPacket  = new PHPDBGPacket (PHPDBGBase.DBGA_STOP);
386
387                 if (proxy.getSocket ().isClosed ()) {                                           // Can we communiate with DBG?
388                         return;                                                 //  No
389                 }
390
391                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
392         }
393
394         /**
395          * This method is called by the proxy.
396          * It sends a request to DBG to get the current variables
397          * with their values. It waits for the response and processes
398          * the input from DBG.
399          *
400          * @param stack The stackframe for which we want the variables.
401          * @return      The array of variables
402          */
403         public Vector getVariables (PHPStackFrame stack) throws IOException, DebugException  {
404                 PHPDBGPacket            DBGPacket;
405                 PHPDBGFrame             DBGFrame1;
406                 PHPDBGEvalString        evalStr;
407
408                 DBGPacket = new PHPDBGPacket (PHPDBGBase.DBGA_REQUEST);     //
409             DBGFrame1 = new PHPDBGFrame (PHPDBGBase.FRAME_EVAL);        //
410
411                 DBGFrame1.addInt (0);                                                                           // istr = raw data ID
412                 DBGFrame1.addInt (1);                                                                           // scope_id = -1 means current location, 0 never used, +1 first depth
413
414                 DBGPacket.addFrame (DBGFrame1);                             // Add command data
415
416                 if (proxy.getSocket ().isClosed ()) {                       // Do we have a socket for DBG communication?
417                         return null;                                                                                    //  No, then leave here
418                 }
419
420                 DBGPacket.sendPacket (os);                                  // Send the request to DBG
421
422                 waitResponse (1000);                                        // Wait for the DBG response (1 second)
423                 flushAllPackets ();                                         // Read and process the response from DBG
424
425                 evalStr         = new PHPDBGEvalString (stack, serGlobals); // Process serialized variables
426                 DBGVarList      = evalStr.getVariables ();
427
428                 if (DBGVarList.size () > 0) {                                                           // Did we get back variables?
429                         PHPVariable var = (PHPVariable) DBGVarList.get (0);             // Yes, then get the first PHPVariable
430                         PHPValue    val = (PHPValue) var.getValue ();           // Get the value
431
432                         if (var.getName ().equals ("")) {                                               // Is the root node an empty node (usually it is)
433                                 DBGVarList = val.getChildVariables ();              // Then remove the empty node.
434                                                                                                                                         // With removing the empty root node, it wouldn't be necessary to
435                                                                                                                                         // set the name to an empty string. So the code below is just for
436                                                                                                                                         // info or in case the users want to have the empty root node.
437
438                                                                                                                                         // The eclipse variable view cannot handle Variables which have an empty name
439                                                                                                                                         // when it comes to variable tree restore operation. Without a name, no restore!
440                                 var.setName (" ");                                                              // Give a name to the variable root node. Even if it is only a space :-)
441                         }                                                                                                               // TODO the best would be to remove the empty root node, but this would
442                                                                                                                                         // require a understanding and reworking of the PHPDBGEvalstring class.
443                 }
444
445                 return DBGVarList;                                                                                      // Return the variables as list
446         }
447
448         /**
449          *
450          * @param logString
451          */
452         public void log(String logString) throws IOException, DebugException  {
453                 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
454                 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_LOG);
455                 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
456
457                 rawCounter++;
458                 DBGFrame1.addInt(rawCounter);                           // ilog
459                 DBGFrame1.addInt(1);                                            // type
460                 DBGFrame1.addInt(0);                                            // mod_no
461                 DBGFrame1.addInt(0);                                            // line_no
462                 DBGFrame1.addInt(0);                                            // imod_name
463                 DBGFrame1.addInt(0);                                            // ext_info
464
465                 DBGFrame2.addInt(rawCounter);                           // FRAME_RAWDATA ID
466                 DBGFrame2.addInt(logString.length() + 1);       // length of rawdata (+ null char)
467                 DBGFrame2.addString(logString);                         // log string
468                 DBGFrame2.addChar('\0');                                        // null char
469
470                 // Add raw data first
471                 DBGPacket.addFrame(DBGFrame2);
472                 // Add command data
473                 DBGPacket.addFrame(DBGFrame1);
474
475                 if (proxy.getSocket ().isClosed ()) {                   // Do we have a socket for DBG communication?
476                         return;                                                                                         //  No, then leave here
477                 }
478
479                 DBGPacket.sendPacket(os);
480
481                 waitResponse(1000);
482                 flushAllPackets();
483         }
484
485         public PHPVariable[] evalBlock(PHPStackFrame stack, String evalString) throws IOException, DebugException  {
486                 PHPDBGPacket DBGPacket= new PHPDBGPacket(PHPDBGBase.DBGA_REQUEST);
487                 PHPDBGFrame DBGFrame1= new PHPDBGFrame(PHPDBGBase.FRAME_EVAL);
488                 PHPDBGFrame DBGFrame2= new PHPDBGFrame(PHPDBGBase.FRAME_RAWDATA);
489
490                 rawCounter++;
491                 DBGFrame1.addInt(rawCounter);                           // istr = raw data ID
492                 DBGFrame1.addInt(1);                                            // scope_id = -1 means current location, 0 never used, +1 first depth
493
494                 DBGFrame2.addInt(rawCounter);                           // FRAME_RAWDATA ID
495                 DBGFrame2.addInt(evalString.length() + 1);      // length of rawdata (+ null char)
496                 DBGFrame2.addString(evalString);                        // eval block
497                 DBGFrame2.addChar('\0');                                        // null char
498
499                 // Add raw data first
500                 DBGPacket.addFrame(DBGFrame2);
501                 // Add command data
502                 DBGPacket.addFrame(DBGFrame1);
503
504                 if (proxy.getSocket ().isClosed ()) {                       // Do we have a socket for DBG communication?
505                         return null;                                                                                    //  No, then leave here
506                 }
507                 DBGPacket.sendPacket(os);
508
509                 waitResponse(1000);
510                 flushAllPackets();
511
512                 PHPDBGEvalString evalStr=new PHPDBGEvalString(stack,evalRet);
513
514                 return evalStr.getVars();
515
516         }
517
518         /**
519          * Read and process everthing we got from DBG
520          */
521         public void flushAllPackets () throws IOException {
522                 while (readResponse() != 0);
523         }
524
525         /**
526          * Get the modules name by its number
527          *
528          * @param modNo The number (id) of the module
529          * @return      The name of the module
530          */
531         public String getModByNo (int modNo) {
532                 int             i;
533                 PHPDBGMod       dbg_mod;
534
535                 for (i = 0; i < DBGMods.size (); i++) {                         // For all the modules we have within the array
536                         dbg_mod = (PHPDBGMod) DBGMods.get (i);                      // Get the module
537
538                         if (dbg_mod.getNo () == modNo) {                            // Is the module from the array the module we want?
539                                 return dbg_mod.getName ();                              //  Yes, return the name of the module
540                         }
541                 }
542
543                 return "";                                                      // If nothing was found return emtpy string
544         }
545
546         /**
547          *
548          * @param  modName The name of the module for which we want the ID
549          * @return
550          * - The ID of the module
551          * - -1 if nothing was found
552          */
553         private int getModByName (String modName) {
554                 int             i;
555                 PHPDBGMod       dbg_mod;
556
557                 for (i = 0; i < DBGMods.size (); i++) {                         // For all the modules we have within the array
558                         dbg_mod = (PHPDBGMod) DBGMods.get (i);                      // Get the module
559
560                         if (dbg_mod.getName ().equalsIgnoreCase (modName)) {            // Is the module from the array the module we want?
561                                 return dbg_mod.getNo ();                                //  Yes, return the name of the module
562                         }
563                 }
564
565                 return -1;                                                      // If nothing was found return -1
566         }
567
568         /**
569          * Return the string for the given frame number
570          *
571          * @param framesInfo The buffer which is to read
572          * @param frameNo    The frame number
573          * @return
574          */
575         private String getRawFrameData (char[] framesInfo, int frameNo) {
576                 int   nextFrame = 0;                                                    // The current read position within the buffer
577                 int[] dbg_frame = new int[2];                                           // The two frame header numbers
578
579                 while (nextFrame < framesInfo.length) {                                 // As long we have something within the buffer
580                         dbg_frame[0] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame);           // The frame type
581                         dbg_frame[1] = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4);       // The frame size
582
583                         nextFrame   += 8;                                                   // The current read position
584
585                         if (dbg_frame[1] == 0) {                                            // If frame size is 0
586                                 return "";                                                      //  return an emtpy string
587                         }
588
589                         switch (dbg_frame[0]) {                                                     // Switch for the frame type
590                                 case PHPDBGBase.FRAME_RAWDATA:                                                  // The only frame type we are interrested in
591                                         if (frameNo == PHPDBGBase.Char4ToInt (framesInfo, nextFrame)) {         // Is it correct  number of the frame
592                                                 int toRead;                                                     //
593
594                                                 toRead = PHPDBGBase.Char4ToInt (framesInfo, nextFrame + 4);     // The size of the string
595
596                                                 return String.copyValueOf (framesInfo, nextFrame + 8, toRead);  // Copy frame content to String and return
597                                         }
598                                         break;
599                         }
600
601                         nextFrame += dbg_frame[1];                                                                      // Go for the next frame (add the length of the current one)
602                 }
603
604                 return "";                                                                                                                                              // We did not found any FRAM_RAWDATA, so return an emtpy strin
605         }
606
607         /**
608          *
609          * The stackList contains the currently read stackframes which were sent
610          * from DBG. The DBG interface holds a list of the active stack frames.
611          * This method replicates the 'static' stackframe list with the DBG stackframe list
612          * Replication is done in the following way:
613          * <ul>
614          * <li> It looks for new stackframes within the DBG stackframe list and
615          *      adds them to the 'static' list.
616          * <li> It looks for stackframes within the 'static' list, and removes them
617          *              from the 'static' list in case the do not appear within the DBG list.
618          * <li> It looks for stackframes which are already existent and replicates the
619          *              line number and the index number.
620          * <li> At the end the 'static' stackfram list has to be sorted by the stackframes
621          *              index numbers.
622          * </ul>
623          *
624          * Removes the unused stackframes from the list, or adds stackframes which
625          * are not yet in the list.
626          *
627          *
628          * @param stackList
629          */
630         private void updateStackFrameList (Vector stackList) {
631                 int                     i;
632                 int             n;
633                 PHPStackFrame   stackFrameNew;
634                 PHPStackFrame   stackFrameOld;
635                 PHPStackFrame[] newStackList;
636
637                 for (i = 0; i < stackList.size (); i++) {                                                               // For all stackList entries
638                         stackFrameNew = (PHPStackFrame) stackList.get(i);
639
640                         for (n = 0; n < stackListOld.size (); n++) {                                    // For all StackFrames in the StackFrame list
641                                 stackFrameOld = (PHPStackFrame) stackListOld.get (n);                   //
642
643                                 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) { // Did we find the sent stackframe within the list of old stackframes?
644                                         stackFrameOld.setLineNumber (stackFrameNew.getLineNumber ());
645                                         stackFrameOld.setIndex (stackFrameNew.getIndex ());
646
647                                         break;                                                                  //  Yes, then break;
648                                 }
649                         }
650
651                         if (n == stackListOld.size ()) {                                    // Did not find the new stackframe within the list
652                                  stackListOld.add (stackFrameNew);                              //  then add the new stackframe
653                         }
654                 }
655
656                 // And now for removing unused stackframes from list
657
658                 for (n = 0; n < stackListOld.size (); n++) {                                            // For all StackFrames in the StackFrame list
659                         stackFrameOld = (PHPStackFrame) stackListOld.get (n);                           //
660
661                         for (i = 0; i < stackList.size (); i++) {                                                       // For all stackList entries
662                                 stackFrameNew = (PHPStackFrame) stackList.get (i);
663
664                                 if (stackFrameNew.getDescription ().equals (stackFrameOld.getDescription ())) { // Did we find the sent stackframe within the list of old stackframes?
665                                         break;                                                                  //  Yes, then break;
666                                 }
667                         }
668
669                         if (i == stackList.size ()) {                                           // Did not find the old stackframe within the list of new ones
670                                  stackListOld.remove (n);                                       //  then remove the old stackframe from list
671                                  n -= 1;                                                        // Adjust the stack list index
672                         }
673                 }
674
675                 Collections.sort (stackListOld);                                                                                // Sort the 'static' stackframe list by the stackframe index numbers.
676                                                                                                                                                                 //
677                 newStackList = new PHPStackFrame[stackListOld.size ()];
678                 newStackList = (PHPStackFrame[]) stackListOld.toArray (newStackList);
679                 DBGStackList = newStackList;
680         }
681
682     /**
683      * Read the response from DBG and process the frame
684      *
685          * @return
686          * - The received command
687          * - or 0 if something was wrong
688      */
689         public int readResponse () throws IOException {
690         int     bytesToRead            = 0;                         // The number of byte to read for the current DBG block
691         int     nextFrame              = 0;                         // The current read position within entirePack
692         int     i                      = 0;
693         int     cmdReceived            = 0;
694         int     stackIndex             = 0;
695         boolean errorStack             = false;
696         char[]  dbg_header_struct_read = new char[16];              // The buffer for the first 16 bytes of a block
697         int[]   dbg_header_struct      = new int[4];                // The first four numbers (long) of a block
698         int[]   dbg_bpl_tmp            = new int[10];
699         int[]   dbg_frame              = new int[2];
700         int[]   dbg_eval_tmp           = new int[3];
701         int[]   dbg_src_tree_tmp       = new int[4];                //
702         int[]   dbg_error_tmp          = new int[2];
703         Vector  rawList                = new Vector();
704         Vector  stackList              = new Vector();              // Intermediate stacklist which is build up in FRAME_STACK frame
705
706         rawList.clear ();
707         stackList.clear ();
708
709                 // Read from input
710         while (readInput (dbg_header_struct_read, 16) != 0) {                               // Read 16 byte from input stream
711                         dbg_header_struct[0] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 0);               // Debug sync header
712             dbg_header_struct[1] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 4);           // Command
713             dbg_header_struct[2] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 8);       //
714             dbg_header_struct[3] = PHPDBGBase.Char4ToInt (dbg_header_struct_read, 12);      // Bytes within this block
715
716             if (dbg_header_struct[0] != 0x5953) {                                           // Check DBG sync bytes
717                 return 0;                                                                   // Wrong header
718             }
719
720             cmdReceived = dbg_header_struct[1];                                             // Get the command
721             setLastCmd (cmdReceived);                                                                                                           // Store the info about the current command
722             bytesToRead = dbg_header_struct[3];                                                                                         // Get the number of bytes to read for this block
723
724                         //System.out.println("Response Received: " + cmdReceived);
725                         char[] entirePack = new char[bytesToRead];                                      // Store the block data into buffer 'entirePack'
726
727             if (bytesToRead > 0) {                                                          // If there is something within the frame
728                 if (readInput (entirePack, bytesToRead) < bytesToRead) {                    // Read the frame into the buffer
729                     return 0;                                                               // We did not read enough bytes, error
730                 }
731                         }
732
733                         nextFrame = 0;                                                                  // Start with the first frame
734
735                         while (nextFrame < bytesToRead) {                                               // As long as we have something within this block
736                                 dbg_frame[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame);                           // The name of the frame
737                                 dbg_frame[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);               // The size of the frame
738                                 nextFrame   += 8;                                                           // The next read position
739
740                                 if (dbg_frame[1] == 0) {                                                    // Something within the frame?
741                                         return 0;                                                               //  Nothing to read, error
742                                 }
743
744                                 switch (dbg_frame[0]) {
745                                         case PHPDBGBase.FRAME_STACK:
746                                                 int[] dbg_stack_new = new int[4];                                       //
747
748                                                 dbg_stack_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);   // Source line number
749                                                 dbg_stack_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);   // Module number
750                                                 dbg_stack_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);   // Scope id
751                                                 dbg_stack_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);  // ID of description string
752
753                                                 if ((dbg_stack_new[1] != 0) && !errorStack) {
754                                                         PHPStackFrame newStack;
755
756                                                         stackIndex++;
757                                                         newStack = new PHPStackFrame (null,                                 // The thread
758                                                                                       getModByNo (dbg_stack_new[1]),        // The name of the module (file)
759                                                                                       dbg_stack_new[0],                     // The source line number
760                                                                                                                   stackIndex,
761                                                                                                                   getRawFrameData (entirePack,          // Get the string from this packet
762                                                                                                                                    dbg_stack_new[3]),   // The frame ID for which we want the string
763                                                                                                                   dbg_stack_new[1]);                                    // The module number
764                                                         stackList.add (newStack);
765                                                 }
766
767                                                 errorStack = false;
768                                                 break;
769
770                                         case PHPDBGBase.FRAME_SOURCE:                                                   // Nothing to be done here
771                                                 break;                                                                      // TODO: what's with that frame? Something interesting
772
773                                         case PHPDBGBase.FRAME_SRC_TREE:                                                 //
774                                                 dbg_src_tree_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);        // The parent module number
775                                                 dbg_src_tree_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);        // The parent line number (not used)
776                                                 dbg_src_tree_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);        // The module number
777                                                 dbg_src_tree_tmp[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);       // The filename number
778
779                                                 if (getModByNo (dbg_src_tree_tmp[2]).equals ("")) {
780                                                         String fileName;
781
782                                                         fileName = new String (getRawFrameData (entirePack, dbg_src_tree_tmp[3]));      // Get the filename
783
784                                                         if (fileName.length () > 0) {                                               // If we have a filename
785                                                                 fileName = fileName.substring (0, fileName.length () - 1);              // Remove '\0' char
786                                                         }
787
788                                                         if (dbg_src_tree_tmp[2] != 0) {                                             // If there is a module number
789                                                                 PHPDBGMod modNew;
790
791                                                                 modNew = new PHPDBGMod (dbg_src_tree_tmp[2], fileName);                 // Create a module object
792
793                                                                 DBGMods.add (modNew);                                                   // And store it to array
794                                                         }
795                                                 }
796                                                 break;
797
798                                         case PHPDBGBase.FRAME_RAWDATA:                                                      // Nothing to be done here
799                                                 break;                                                                          //  FRAME_RAWDATA are processed within getRawFrameData
800
801                                         case PHPDBGBase.FRAME_ERROR:                                                                                                            // An error frame
802                                                 errorStack       = true;                                                                                                                // Yes, we have an error stack
803                                                 dbg_error_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);                   // Error type
804                                                 dbg_error_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);                   // Error message ID
805
806                                                 String error = "\n";                                                            //
807
808                                                 switch (dbg_error_tmp[0]) {                                                                                                             // Switch on error type
809                                                         case PHPDBGBase.E_ERROR:                        error += "[Error]";                     break;
810                                                         case PHPDBGBase.E_WARNING:                      error += "[Warning]";                   break;
811                                                         case PHPDBGBase.E_PARSE:                        error += "[Parse Error]";               break;
812                                                         case PHPDBGBase.E_NOTICE:                       error += "[Notice]";                    break;
813                                                         case PHPDBGBase.E_CORE_ERROR:           error += "[Core Error]";                break;
814                                                         case PHPDBGBase.E_CORE_WARNING:         error += "[Core Warning]";              break;
815                                                         case PHPDBGBase.E_COMPILE_ERROR:        error += "[Compile Error]";             break;
816                                                         case PHPDBGBase.E_COMPILE_WARNING:      error += "[Compile Warning]";   break;
817                                                         case PHPDBGBase.E_USER_ERROR:           error += "[User Error]";                break;
818                                                         case PHPDBGBase.E_USER_WARNING:         error += "[User Warning]";              break;
819                                                         case PHPDBGBase.E_USER_NOTICE:          error += "[User Notice]";               break;
820                                                         default:                                                        error += "[Unexpected Error]";  break;
821                                                 }
822
823                                                 error += ": ";
824                                                 error += new String (getRawFrameData (entirePack, dbg_error_tmp[1]));                   // Add the error string for this error message ID
825
826                                                 if (error.length () > 0) {                                                                                                              // If we have a error message
827                                                          error = error.substring (0, error.length () - 1);                                                      //  Remove '\0' char
828                                                 }
829
830                                                 error += "\n";                                                                  // Append a CR
831
832                                                 PHPDebugCorePlugin.log (new DebugException (new Status (IStatus.WARNING,
833                                                                                                         PHPDebugCorePlugin.PLUGIN_ID,
834                                                                                                                                                                 IStatus.OK,
835                                                                                                                                                                 error, null)));
836
837                                                 // To print errors on the console, I must execute a code in the
838                                                 // php context, that write the stderr... I didn't found a better way
839                                                 // TODO: Find a better way????
840
841 //                                              String codeExec= "";
842 //                                              codeExec= "fwrite(fopen('php://stderr', 'w'),\\\"" + error + "\\\");";
843 //                                              try {
844 //                                                      evalBlock("eval(\"" + codeExec + "\");");
845 //                                              } catch (DebugException e) {
846 //                                                      PHPDebugCorePlugin.log(e);
847 //                                              }
848 //
849                                                 if (!stopOnError) {                                                             // Is always false (Did not see where this is set to true!?)
850                                                         if (lastCommand.equals (PHPDBGBase.DBGA_CONTINUE)) {                        // If last command for PHP was a 'continue',
851                                                                 continueExecution ();                                                   //  send continue again
852                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPINTO)) {                 // If last command for PHP was a 'step into',
853                                                                 stepInto ();                                                            //  send 'step into' again
854                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOUT)) {                  // If last command for PHP was a 'step out',
855                                                                 stepOut ();                                                             //  send 'step out' again
856                                                         } else if (lastCommand.equals (PHPDBGBase.DBGA_STEPOVER)) {                 // If last command for PHP was a 'step over',
857                                                                 stepOver ();                                                            //  send 'step over' again
858                                                         }
859                                                 }
860                                                 break;
861
862                                         case PHPDBGBase.FRAME_EVAL:
863                                                 String evalString;
864
865                                                 evalString      = new String ("");
866                                                 dbg_eval_tmp[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);                    // istr
867                                                 dbg_eval_tmp[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);                    // iresult
868                                                 dbg_eval_tmp[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);                    // ierror
869
870                                                 evalRet                 = getRawFrameData (entirePack, dbg_eval_tmp[1]);                //
871                                                 evalString              = getRawFrameData (entirePack, dbg_eval_tmp[0]);                //
872                                                 serGlobals              = evalRet;                                                      //
873                                                 break;
874
875                                         case PHPDBGBase.FRAME_BPS:                                                          //
876                                                 break;                                                                          //
877
878                                         case PHPDBGBase.FRAME_BPL:
879                                                 int[] dbg_bpl_new;
880
881                                                 dbg_bpl_new        = new int[10];
882                                                 dbg_bpl_new[0] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 0);
883                                                 dbg_bpl_new[1] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 4);
884                                                 dbg_bpl_new[2] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 8);
885                                                 dbg_bpl_new[3] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 12);
886                                                 dbg_bpl_new[4] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 16);
887                                                 dbg_bpl_new[5] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 20);
888                                                 dbg_bpl_new[6] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 24);
889                                                 dbg_bpl_new[7] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 28);
890                                                 dbg_bpl_new[8] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 32);
891                                                 dbg_bpl_new[9] = PHPDBGBase.Char4ToInt (entirePack, nextFrame + 36);
892
893                                                 // look if breakpoint already exists in vector
894                                                 for (i = 0; i < DBGBPList.size (); i++) {
895                                                         dbg_bpl_tmp = (int[]) DBGBPList.get (i);
896
897                                                         if (dbg_bpl_tmp[8] == dbg_bpl_new[8]) {
898                                                                 DBGBPList.remove (i);
899
900                                                                 break;
901                                                         }
902                                                 }
903
904                                                 // add breakpoint to vector
905                                                 DBGBPList.add (dbg_bpl_new);
906                                                 copyToLastBP (dbg_bpl_new);
907
908                                                 // mod no returned?
909                                                 if (getModByNo (dbg_bpl_new[0]).equals ("")) {
910                                                         String fileName;
911
912                                                         fileName = new String (getRawFrameData (entirePack, dbg_bpl_new[2]));
913
914                                                         if (fileName.length () > 0) {                                               // If we have filename
915                                                                 fileName = fileName.substring (0, fileName.length () - 1);                              //  Remove '\0' char
916                                                         }
917
918                                                         if (dbg_bpl_new[0] != 0) {
919                                                                 PHPDBGMod modNew;
920
921                                                                 modNew = new PHPDBGMod (dbg_bpl_new[0], fileName);
922
923                                                                 DBGMods.add (modNew);
924                                                         }
925                                                 }
926                                                 break;
927
928                                         case PHPDBGBase.FRAME_VER:
929                                                 break;
930
931                                         case PHPDBGBase.FRAME_SID:
932                                                 sid = PHPDBGBase.Char4ToInt(entirePack, nextFrame + 0);
933                                                 break;
934
935                                         case PHPDBGBase.FRAME_SRCLINESINFO:
936                                                 break;
937
938                                         case PHPDBGBase.FRAME_SRCCTXINFO:
939                                                 break;
940
941                                         case PHPDBGBase.FRAME_LOG:
942                                                 break;
943
944                                         case PHPDBGBase.FRAME_PROF:
945                                                 break;
946
947                                         case PHPDBGBase.FRAME_PROF_C:
948                                                 break;
949
950                                         case PHPDBGBase.FRAME_SET_OPT:
951                                                 break;
952                                 }
953
954                                 nextFrame += dbg_frame[1];                                                      // go to next frame
955                         }
956
957                         // Now process command
958                         switch(cmdReceived) {
959                                 case PHPDBGBase.DBGC_REPLY:
960                                         break;
961
962                                 case PHPDBGBase.DBGC_STARTUP:
963                                         break;
964
965                                 case PHPDBGBase.DBGC_END:
966                                         sessionEnded = true;
967                                         break;
968
969                                 case PHPDBGBase.DBGC_BREAKPOINT:
970                                         BPUnderHit   = getBPUnderHit ();
971                                         updateStackFrameList (stackList);
972                                         break;
973
974                                 case PHPDBGBase.DBGC_STEPINTO_DONE:
975                                 case PHPDBGBase.DBGC_STEPOVER_DONE:
976                                 case PHPDBGBase.DBGC_STEPOUT_DONE:
977                                 case PHPDBGBase.DBGC_EMBEDDED_BREAK:
978                                 case PHPDBGBase.DBGC_PAUSE:
979                                         BPUnderHit   = 1;
980                                         updateStackFrameList (stackList);
981                                         break;
982
983                                 case PHPDBGBase.DBGC_ERROR:
984                                         stackList.clear ();
985                                         updateStackFrameList (stackList);
986                                         break;
987
988                                 case PHPDBGBase.DBGC_LOG:
989                                         break;
990
991                                 case PHPDBGBase.DBGC_SID:
992                                         break;
993                         }
994                 }
995
996                 return cmdReceived;                                         // Return the command we received with this block
997         }
998
999     /**
1000      *
1001      */
1002
1003         public PHPStackFrame[] getStackList() {
1004                 return DBGStackList;
1005         }
1006
1007         /**
1008          * Reads from input buffer (response sent from DBG) the given number of chars
1009          * into frame buffer.
1010          *
1011          * @param buffer  The frame buffer where to store the read data from DBG.
1012          * @param bytes   The number of bytes (chars) which are to read from input stream.
1013          * @return        The number of bytes actually read.
1014          */
1015         private int readInput (char[] buffer, int bytes) throws IOException {
1016                 int bytesRead = 0;                                                                                      // Reset the bytes read counter
1017
1018                 for (int i = 0; i < bytes; i++) {                           // For the number of bytes we should read
1019                         if (in.ready ()) {                                                                              // If input stream is ready for reading
1020                                 buffer[i] = (char) (in.read () & 0x00FF);           // Read a char and store only the least significant 8-bits
1021                                 bytesRead++;                                        // Increment the bytes read counter
1022                         }
1023                         else {                                                  // Input stream is not ready
1024                                 break;                                              // Break the loop
1025                         }
1026                 }
1027
1028                 return bytesRead;                                                                                       // Return the number of bytes actually read
1029         }
1030
1031         /**
1032          * PHPProxy could stop the waiting for a response with this method.
1033          *
1034          */
1035         public void setShouldStop () {
1036                 this.shouldStop = true;
1037         }
1038
1039         /**
1040          * @param milliseconds The maximum time in milliseconds we wait for something
1041          *                     to be send from DBG.
1042          * @return             - true if something was received from DBG
1043          *                                         - false if nothing was send from DBG within the given time
1044          *
1045          */
1046         public boolean waitResponse (long milliseconds) throws IOException {
1047                 long timeout;
1048
1049                 timeout = System.currentTimeMillis () + milliseconds;           // Calculate the system time till we wait.
1050
1051                 while (System.currentTimeMillis () < timeout) {             // Is waiting time running out?
1052                         if (in.ready () || shouldStop) {                        //  No, so did we get something or should we stop now
1053                                 break;                                              //   Yes, break the waiting
1054                         }
1055                 }
1056
1057                 return in.ready ();                                         // true if we got something from DBG
1058         }
1059 }