3 // Copyright by Johannes Sixt, Keith Isdale
4 // This file is under GPL, the GNU General Public Licence
6 #include "xsldbgdriver.h"
8 #include <qstringlist.h>
9 #include <klocale.h> /* i18n */
11 #include <stdlib.h> /* strtol, atoi */
12 #include <string.h> /* strcpy */
13 #include <kmessagebox.h>
22 static VarTree
*parseVar(const char *&s
);
23 static bool parseName(const char *&s
, QString
& name
,
24 VarTree::NameKind
& kind
);
25 static bool parseValue(const char *&s
, VarTree
* variable
);
26 static bool isErrorExpr(const char *output
);
28 #define TERM_IO_ALLOWED 1
30 // TODO: make this cmd info stuff non-static to allow multiple
31 // simultaneous gdbs to run!
33 struct XsldbgCmdInfo
{
35 const char *fmt
; /* format string */
37 argNone
, argString
, argNum
,
38 argStringNum
, argNumString
,
44 * The following array of commands must be sorted by the DC* values,
45 * because they are used as indices.
47 static XsldbgCmdInfo cmds
[] = {
48 {DCinitialize
, "init\n", XsldbgCmdInfo::argNone
},
49 {DCtty
, "tty %s\n", XsldbgCmdInfo::argString
},
50 {DCexecutable
, "source %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
51 {DCtargetremote
, "print 'target remote %s'\n", XsldbgCmdInfo::argString
},
52 {DCcorefile
, "data %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
53 {DCattach
, "print 'attach %s'\n", XsldbgCmdInfo::argString
},
54 {DCinfolinemain
, "print 'info main line'\n", XsldbgCmdInfo::argNone
},
55 {DCinfolocals
, "locals -f\n", XsldbgCmdInfo::argNone
},
56 {DCinforegisters
, "print 'info reg'\n", XsldbgCmdInfo::argNone
},
57 {DCexamine
, "print 'x %s %s'\n", XsldbgCmdInfo::argString2
},
58 {DCinfoline
, "print 'templates %s:%d'\n", XsldbgCmdInfo::argStringNum
},
59 {DCdisassemble
, "print 'disassemble %s %s'\n", XsldbgCmdInfo::argString2
},
60 {DCsetargs
, "data %s\n", XsldbgCmdInfo::argString
},
61 {DCsetenv
, "addparam %s %s\n", XsldbgCmdInfo::argString2
},
62 {DCunsetenv
, "unset env %s\n", XsldbgCmdInfo::argString
},
63 {DCsetoption
, "setoption %s %d\n", XsldbgCmdInfo::argStringNum
},
64 {DCcd
, "chdir %s\n", XsldbgCmdInfo::argString
},
65 {DCbt
, "where\n", XsldbgCmdInfo::argNone
},
66 {DCrun
, "run\nsource\n", XsldbgCmdInfo::argNone
}, /* Ensure that at the start
67 of executing XSLT we show the XSLT file */
68 {DCcont
, "continue\n", XsldbgCmdInfo::argNone
},
69 {DCstep
, "step\n", XsldbgCmdInfo::argNone
},
70 {DCstepi
, "step\n", XsldbgCmdInfo::argNone
},
71 {DCnext
, "next\n", XsldbgCmdInfo::argNone
},
72 {DCnexti
, "next\n", XsldbgCmdInfo::argNone
},
73 {DCfinish
, "stepup\n", XsldbgCmdInfo::argNone
},
74 {DCuntil
, "continue %s:%d\n", XsldbgCmdInfo::argStringNum
},
75 {DCkill
, "quit\n", XsldbgCmdInfo::argNone
},
76 {DCbreaktext
, "break %s\n", XsldbgCmdInfo::argString
},
77 {DCbreakline
, "break -l %s %d\n", XsldbgCmdInfo::argStringNum
},
78 {DCtbreakline
, "break -l %s %d\n", XsldbgCmdInfo::argStringNum
},
79 {DCbreakaddr
, "print `break *%s`\n", XsldbgCmdInfo::argString
},
80 {DCtbreakaddr
, "print `tbreak *%s`\n", XsldbgCmdInfo::argString
},
81 {DCwatchpoint
, "print 'watch %s'\n", XsldbgCmdInfo::argString
},
82 {DCdelete
, "delete %d\n", XsldbgCmdInfo::argNum
},
83 {DCenable
, "enable %d\n", XsldbgCmdInfo::argNum
},
84 {DCdisable
, "disable %d\n", XsldbgCmdInfo::argNum
},
85 {DCprint
, "print %s\n", XsldbgCmdInfo::argString
},
86 {DCprintDeref
, "print 'print (*%s)'\n", XsldbgCmdInfo::argString
},
87 {DCprintStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
88 {DCprintQStringStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
89 {DCframe
, "frame %d\n", XsldbgCmdInfo::argNum
},
90 {DCfindType
, "print 'whatis %s'\n", XsldbgCmdInfo::argString
},
91 {DCinfosharedlib
, "stylesheets\n", XsldbgCmdInfo::argNone
},
92 {DCthread
, "print 'thread %d'\n", XsldbgCmdInfo::argNum
},
93 {DCinfothreads
, "print 'info threads'\n", XsldbgCmdInfo::argNone
},
94 {DCinfobreak
, "show\n", XsldbgCmdInfo::argNone
},
95 {DCcondition
, "print 'condition %d %s'\n", XsldbgCmdInfo::argNumString
},
96 {DCsetpc
, "print 'set variable $pc=%s'\n", XsldbgCmdInfo::argString
},
97 {DCignore
, "print 'ignore %d %d'\n", XsldbgCmdInfo::argNum2
},
98 {DCsetvariable
, "set %s %s\n", XsldbgCmdInfo::argString2
},
101 #define NUM_CMDS (int(sizeof(cmds)/sizeof(cmds[0])))
102 #define MAX_FMTLEN 200
104 XsldbgDriver::XsldbgDriver():
105 DebuggerDriver(), m_gdbMajor(2), m_gdbMinor(0)
107 m_promptRE
.setPattern("\\(xsldbg\\) .*> ");
109 m_promptLastChar
= ' ';
111 m_markerRE
.setPattern("^Breakpoint for file ");
112 m_haveDataFile
= FALSE
;
115 // check command info array
118 for (int i
= 0; i
< NUM_CMDS
; i
++) {
119 // must be indexable by DbgCommand values, i.e. sorted by DbgCommand values
120 assert(i
== cmds
[i
].cmd
);
121 // a format string must be associated
122 assert(cmds
[i
].fmt
!= 0);
123 assert(strlen(cmds
[i
].fmt
) <= MAX_FMTLEN
);
124 // format string must match arg specification
125 switch (cmds
[i
].argsNeeded
) {
126 case XsldbgCmdInfo::argNone
:
127 assert(strchr(cmds
[i
].fmt
, '%') == 0);
129 case XsldbgCmdInfo::argString
:
130 perc
= strchr(cmds
[i
].fmt
, '%');
131 assert(perc
!= 0 && perc
[1] == 's');
132 assert(strchr(perc
+ 2, '%') == 0);
134 case XsldbgCmdInfo::argNum
:
135 perc
= strchr(cmds
[i
].fmt
, '%');
136 assert(perc
!= 0 && perc
[1] == 'd');
137 assert(strchr(perc
+ 2, '%') == 0);
139 case XsldbgCmdInfo::argStringNum
:
140 perc
= strchr(cmds
[i
].fmt
, '%');
141 assert(perc
!= 0 && perc
[1] == 's');
142 perc
= strchr(perc
+ 2, '%');
143 assert(perc
!= 0 && perc
[1] == 'd');
144 assert(strchr(perc
+ 2, '%') == 0);
146 case XsldbgCmdInfo::argNumString
:
147 perc
= strchr(cmds
[i
].fmt
, '%');
148 assert(perc
!= 0 && perc
[1] == 'd');
149 perc
= strchr(perc
+ 2, '%');
150 assert(perc
!= 0 && perc
[1] == 's');
151 assert(strchr(perc
+ 2, '%') == 0);
153 case XsldbgCmdInfo::argString2
:
154 perc
= strchr(cmds
[i
].fmt
, '%');
155 assert(perc
!= 0 && perc
[1] == 's');
156 perc
= strchr(perc
+ 2, '%');
157 assert(perc
!= 0 && perc
[1] == 's');
158 assert(strchr(perc
+ 2, '%') == 0);
160 case XsldbgCmdInfo::argNum2
:
161 perc
= strchr(cmds
[i
].fmt
, '%');
162 assert(perc
!= 0 && perc
[1] == 'd');
163 perc
= strchr(perc
+ 2, '%');
164 assert(perc
!= 0 && perc
[1] == 'd');
165 assert(strchr(perc
+ 2, '%') == 0);
172 XsldbgDriver::~XsldbgDriver()
178 XsldbgDriver::driverName() const
184 XsldbgDriver::defaultXsldbg()
186 return "xsldbg --lang en --shell --gdb";
190 XsldbgDriver::defaultInvocation() const
192 return defaultXsldbg();
195 QStringList
XsldbgDriver::boolOptionList() const
197 QStringList allOptions
;
198 allOptions
.append("verbose");
199 allOptions
.append("repeat");
200 allOptions
.append("debug");
201 allOptions
.append("novalid");
202 allOptions
.append("noout");
203 allOptions
.append("html");
204 allOptions
.append("docbook");
205 allOptions
.append("nonet");
206 allOptions
.append("catalogs");
207 allOptions
.append("xinclude");
208 allOptions
.append("profile");
214 XsldbgDriver::slotReceiveOutput(KProcess
* process
, char *buffer
,
218 if (m_state
!= DSidle
) {
220 DebuggerDriver::slotReceiveOutput(process
, buffer
, buflen
);
222 if (strncmp(buffer
, "quit", 4) == 0) {
223 TRACE("Ignoring text when xsldbg is quiting");
226 ("Stray output received by XsldbgDriver::slotReceiveOutput");
233 XsldbgDriver::startup(QString cmdStr
)
235 if (!DebuggerDriver::startup(cmdStr
))
238 static const char xsldbgInitialize
[] = "pwd\nsetoption gdb 2\n"; /* don't need to do anything else */
240 executeCmdString(DCinitialize
, xsldbgInitialize
, false);
246 XsldbgDriver::commandFinished(CmdQueueItem
* cmd
)
249 TRACE(__PRETTY_FUNCTION__
);
250 // command string must be committed
251 if (!cmd
->m_committed
) {
254 (__PRETTY_FUNCTION__
+
255 (" with uncommited command:\n\t" + cmd
->m_cmdString
)));
259 switch (cmd
->m_cmd
) {
261 // get version number from preamble
264 QRegExp
xsldbgVersion("^XSLDBG [0-9]+\\.[0-9]+\\.[0-9]+");
265 int offset
= xsldbgVersion
.match(m_output
, 0, &len
);
268 char *start
= m_output
+ offset
+ 7; // skip "^XSLDBG "
271 TRACE("Reading version");
273 m_gdbMajor
= strtol(start
, &end
, 10);
274 m_gdbMinor
= strtol(end
+ 1, 0, 10); // skip "."
276 // nothing was parsed
281 // assume some default version (what would make sense?)
285 TRACE(QString("Got version ") +
286 QString::number(m_gdbMajor
) + "." +
287 QString::number(m_gdbMinor
));
292 /* ok, the command is ready */
293 emit
commandReceived(cmd
, m_output
);
295 switch (cmd
->m_cmd
) {
303 if (!::isErrorExpr(m_output
))
306 // This only shows an error for DCinfolocals
307 // need to update KDebugger::handleRunCommand ?
308 KMessageBox::sorry(0L, m_output
);
314 if (!m_xslFile
.isEmpty())
315 emit
activateFileLine(m_xslFile
, 0, DbgAddr());
323 XsldbgDriver::parseMarker()
326 // TRACE("parseMarker : xsldbg");
328 int len
, markerStart
= -1;
331 while (markerStart
== -1) {
332 if ((p
== 0) || (*p
== '\0')) {
336 //TRACE(QString("parseMarker is looking at :") + p);
337 markerStart
= m_markerRE
.match(p
, 0, &len
);
338 if (markerStart
== -1) {
339 // try to marker on next line !
341 if ((p
!= 0) && (*p
!= '\0'))
347 // extract the marker
348 char *startMarker
= p
+ markerStart
+ len
;
350 //TRACE(QString("found marker:") + startMarker);
351 char *endMarker
= strchr(startMarker
, '\n');
358 // extract filename and line number
359 static QRegExp
MarkerRE(" at line [0-9]+");
361 int lineNoStart
= MarkerRE
.match(startMarker
, 0, &len
);
363 if (lineNoStart
>= 0) {
364 int lineNo
= atoi(startMarker
+ lineNoStart
+ 8);
368 // now show the window
369 startMarker
[lineNoStart
-1] = '\0'; /* split off file name */
370 TRACE("Got file and line number");
372 TRACE(QString(startMarker
) + ": " + QString::number(lineNo
));
373 emit
activateFileLine(startMarker
, lineNo
- 1, address
);
379 * Escapes characters that might lead to problems when they appear on gdb's
383 normalizeStringArg(QString
& arg
)
386 * Remove trailing backslashes. This approach is a little simplistic,
387 * but we know that there is at the moment no case where a trailing
388 * backslash would make sense.
390 while (!arg
.isEmpty() && arg
[arg
.length() - 1] == '\\') {
391 arg
= arg
.left(arg
.length() - 1);
397 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
)
399 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
400 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString
);
402 normalizeStringArg(strArg
);
405 // need the working directory when parsing the output
406 m_programWD
= strArg
;
407 } else if (cmd
== DCexecutable
) {
408 // want to display the XSL file
412 SIZED_QString(cmdString
, MAX_FMTLEN
+ strArg
.length());
413 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.latin1());
418 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg
)
420 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
421 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum
);
423 SIZED_QString(cmdString
, MAX_FMTLEN
+ 30);
425 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
);
430 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
, int intArg
)
432 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
433 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
||
434 cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNumString
||
435 cmd
== DCexamine
|| cmd
== DCtty
);
437 normalizeStringArg(strArg
);
439 SIZED_QString(cmdString
, MAX_FMTLEN
+ 30 + strArg
.length());
443 * intArg specifies which channels should be redirected to
444 * /dev/null. It is a value or'ed together from RDNstdin,
445 * RDNstdout, RDNstderr.
447 static const char *const runRedir
[8] = {
451 " </dev/null >/dev/null",
453 " </dev/null 2>/dev/null",
455 " </dev/null >/dev/null 2>&1"
458 if (strArg
.isEmpty())
459 intArg
= 7; /* failsafe if no tty */
460 m_redirect
= runRedir
[intArg
& 7];
462 return makeCmdString(DCtty
, strArg
); /* note: no problem if strArg empty */
465 if (cmd
== DCexamine
) {
466 // make a format specifier from the intArg
467 static const char size
[16] = {
468 '\0', 'b', 'h', 'w', 'g'
470 static const char format
[16] = {
471 '\0', 'x', 'd', 'u', 'o', 't',
472 'a', 'c', 'f', 's', 'i'
475 assert(MDTsizemask
== 0xf); /* lowest 4 bits */
476 assert(MDTformatmask
== 0xf0); /* next 4 bits */
477 int count
= 16; /* number of entities to print */
478 char sizeSpec
= size
[intArg
& MDTsizemask
];
479 char formatSpec
= format
[(intArg
& MDTformatmask
) >> 4];
481 assert(sizeSpec
!= '\0');
482 assert(formatSpec
!= '\0');
483 // adjust count such that 16 lines are printed
484 switch (intArg
& MDTformatmask
) {
487 break; /* no modification needed */
489 // all cases drop through:
490 switch (intArg
& MDTsizemask
) {
503 spec
.sprintf("/%d%c%c", count
, sizeSpec
, formatSpec
);
505 return makeCmdString(DCexamine
, spec
, strArg
);
508 if (cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
) {
509 // line numbers are zero-based
510 if (cmd
== DCuntil
|| cmd
== DCbreakline
||
511 cmd
== DCtbreakline
|| cmd
== DCinfoline
) {
514 if (cmd
== DCinfoline
) {
515 // must split off file name part
516 int slash
= strArg
.findRev('/');
519 strArg
= strArg
.right(strArg
.length() - slash
- 1);
521 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.latin1(), intArg
);
523 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
, strArg
.latin1());
529 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg1
,
532 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
533 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString2
);
535 normalizeStringArg(strArg1
);
536 normalizeStringArg(strArg2
);
538 SIZED_QString(cmdString
,
539 MAX_FMTLEN
+ strArg1
.length() + strArg2
.length());
540 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg1
.latin1(), strArg2
.latin1());
545 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg1
, int intArg2
)
547 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
548 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum2
);
550 SIZED_QString(cmdString
, MAX_FMTLEN
+ 60);
551 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg1
, intArg2
);
556 XsldbgDriver::executeCmd(DbgCommand cmd
, bool clearLow
)
558 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
559 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNone
);
562 m_haveCoreFile
= false;
565 return executeCmdString(cmd
, cmds
[cmd
].fmt
, clearLow
);
569 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, bool clearLow
)
571 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
), clearLow
);
575 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg
, bool clearLow
)
578 return executeCmdString(cmd
, makeCmdString(cmd
, intArg
), clearLow
);
582 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, int intArg
,
585 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
),
590 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
593 return executeCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
),
598 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg1
, int intArg2
,
601 return executeCmdString(cmd
, makeCmdString(cmd
, intArg1
, intArg2
),
606 XsldbgDriver::queueCmd(DbgCommand cmd
, QueueMode mode
)
608 return queueCmdString(cmd
, cmds
[cmd
].fmt
, mode
);
612 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, QueueMode mode
)
614 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
), mode
);
618 XsldbgDriver::queueCmd(DbgCommand cmd
, int intArg
, QueueMode mode
)
620 return queueCmdString(cmd
, makeCmdString(cmd
, intArg
), mode
);
624 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, int intArg
,
627 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
), mode
);
631 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
634 return queueCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
), mode
);
638 XsldbgDriver::terminate()
640 qDebug("XsldbgDriver::Terminate");
642 executeCmdString(DCinitialize
, "quit\n", true);
648 XsldbgDriver::detachAndTerminate()
650 qDebug("XsldbgDriver::detachAndTerminate");
652 executeCmdString(DCinitialize
, "quit\n", true);
657 XsldbgDriver::interruptInferior()
659 // remove accidentally queued commands
660 qDebug("interruptInferior");
666 isErrorExpr(const char *output
)
670 #define ERROR_WORD_COUNT 6
671 static const char *errorWords
[ERROR_WORD_COUNT
] = {
673 "error:", // libxslt error
676 "warning:", // libxslt warning
677 "Information:" // xsldbg information
679 static int errorWordLength
[ERROR_WORD_COUNT
] = {
682 15, /* Unknown command*/
688 for (wordIndex
= 0; wordIndex
< ERROR_WORD_COUNT
; wordIndex
++){
690 errorWords
[wordIndex
],
691 errorWordLength
[wordIndex
]) == 0){
693 TRACE(QString("Error/Warning/Information from xsldbg ") + output
);
702 * Returns true if the output is an error message. If wantErrorValue is
703 * true, a new VarTree object is created and filled with the error message.
706 parseErrorMessage(const char *output
,
707 VarTree
* &variable
, bool wantErrorValue
)
709 if (isErrorExpr(output
)) {
710 if (wantErrorValue
) {
711 // put the error message as value in the variable
712 variable
= new VarTree(QString(), VarTree::NKplain
);
713 const char *endMsg
= strchr(output
, '\n');
716 endMsg
= output
+ strlen(output
);
717 variable
->m_value
= FROM_LATIN1(output
, endMsg
- output
);
728 XsldbgDriver::setPrintQStringDataCmd(const char* /*cmd*/)
733 XsldbgDriver::parseQCharArray(const char */
*output*/
, bool /*wantErrorValue*/,
736 VarTree
*variable
= 0;
738 TRACE("XsldbgDriver::parseQCharArray not implmented");
743 parseVar(const char *&s
)
746 bool foundLocalVar
= false;
747 VarTree
*variable
= 0L;
750 VarTree::NameKind kind
;
752 TRACE(__PRETTY_FUNCTION__
);
755 if (parseErrorMessage(p
, variable
, false) == true) {
756 TRACE("Found error message");
760 if (strncmp(p
, " Local", 6) == 0) {
761 foundLocalVar
= true;
764 TRACE("Found local variable");
765 } else if (strncmp(p
, " Global", 7) == 0) {
768 TRACE("Found global variable");
769 } else if (strncmp(p
, "= ", 2) == 0) {
770 /* we're processing the result of a "print command" */
772 char *nextLine
= strchr(p
, '\n');
774 TRACE("Found print expr");
776 p
= p
+ 2; /* skip the "= " */
777 name
= FROM_LATIN1(p
, nextLine
- p
);
778 kind
= VarTree::NKplain
;
780 variable
= new VarTree(name
, kind
);
781 variable
->m_varKind
= VarTree::VKsimple
;
782 variable
->setDeleteChildren(true);
783 parseValue(p
, variable
);
787 return variable
; /* don't know what to do this this data abort!! */
794 // No value provided just a name
795 TRACE(QString("Parse var: name") + p
);
796 if (!parseName(p
, name
, kind
)) {
799 variable
= new VarTree(name
, kind
);
800 if (variable
!= 0L) {
801 variable
->m_varKind
= VarTree::VKsimple
;
802 variable
->setDeleteChildren(true);
809 TRACE(QString("Parse var: name") + p
);
810 if (!parseName(p
, name
, kind
)) {
813 variable
= new VarTree(name
, kind
);
814 if (variable
!= 0L) {
815 variable
->m_varKind
= VarTree::VKsimple
;
816 variable
->setDeleteChildren(true);
820 if (!parseValue(p
, variable
)) {
835 skipName(const char *&p
)
837 // allow : (for enumeration values) and $ and . (for _vtbl.)
838 while (isalnum(*p
) || *p
== '_' || *p
== ':' || *p
== '$' || *p
== '.')
843 parseName(const char *&s
, QString
& name
, VarTree::NameKind
& kind
)
845 /* qDebug(__PRETTY_FUNCTION__); */
846 kind
= VarTree::NKplain
;
851 // examples of names:
854 while ((*p
!= '\n') && (*p
!= '\0')) {
860 name
= FROM_LATIN1(s
, len
);
861 /* XSL variables will have a $ prefix to be evaluated
863 //TRACE(QString("parseName got name" ) + name);
865 // return the new position
871 parseValue(const char *&s
, VarTree
* variable
)
873 const char *start
= s
, *end
= s
;
874 VarTree
* childValue
;
875 #define VALUE_END_MARKER_INDEX 0
877 /* This mark the end of a value */
878 static const char *marker
[] = {
879 "\032\032", /* value end marker*/
881 "Breakpoint at", /* stepped to next location */
882 "Breakpoint in", /* reached a set breakpoint */
883 "Reached ", /* reached template */
891 static char valueBuffer
[2048];
892 int markerIndex
= 0, foundEnd
= 0;
896 return false; /* should never happen but .. */
898 while (start
&& (*start
!= '\0')) {
899 /* look for the next marker */
900 for (markerIndex
= 0; marker
[markerIndex
] != 0; markerIndex
++) {
902 strncmp(start
, marker
[markerIndex
],
903 strlen(marker
[markerIndex
])) == 0;
912 end
= strchr(start
, '\n');
914 copySize
= end
- start
;
916 copySize
= strlen(start
);
917 if (copySize
>= sizeof(valueBuffer
))
918 copySize
= sizeof(valueBuffer
)-1;
920 strncpy(valueBuffer
, start
, copySize
);
921 valueBuffer
[copySize
] = '\0';
922 TRACE("Got value :");
924 if ((variable
->m_varKind
== VarTree::VKsimple
)) {
925 if (!variable
->m_value
.isEmpty()){
926 variable
->m_varKind
= VarTree::VKarray
;
927 childValue
= new VarTree(variable
->m_value
, VarTree::NKplain
);
928 variable
->appendChild(childValue
);
929 childValue
= new VarTree(valueBuffer
, VarTree::NKplain
);
930 variable
->appendChild(childValue
);
931 variable
->m_value
= "";
933 variable
->m_value
= valueBuffer
;
936 childValue
= new VarTree(valueBuffer
, VarTree::NKplain
);
937 variable
->appendChild(childValue
);
949 TRACE(QString("Unable to find end on value near :") + start
);
951 // If we've got something otherthan a end of value marker then
952 // advance to the end of this buffer
953 if (markerIndex
!= VALUE_END_MARKER_INDEX
){
954 while (start
&& *start
!= '\0')
957 start
= start
+ strlen(marker
[0]);
967 * Parses a stack frame.
970 parseFrameInfo(const char *&s
, QString
& func
,
971 QString
& file
, int &lineNo
, DbgAddr
& /*address*/)
973 const char *p
= s
, *endPos
= s
+ strlen(s
);
974 QString lineNoString
;
976 TRACE("parseFrameInfo");
980 /* skip 'template :\" */
984 while ((*p
!= '\"') && (*p
!= '\0')) {
988 while ((*p
!= '\0') && *p
!= '"')
998 /* skip mode :".*" */
999 while ((*p
!= '\0') && *p
!= '"')
1003 while ((*p
!= '\0') && *p
!= '"')
1006 /* skip '" in file ' */
1012 while (!isspace(*p
) && (*p
!= '\"') && (*p
!= '\0')) {
1018 ASSERT(p
<= endPos
);
1025 /* skip ' : line '" */
1028 ASSERT(p
<= endPos
);
1035 /* KDbg uses an offset of +1 for its line numbers */
1036 lineNo
= atoi(p
) - 1;
1037 lineNoString
= QString::number(lineNo
);
1039 /* convert func into format needed */
1040 func
.append(" at ");
1043 func
.append(lineNoString
);
1045 /*advance to next line */
1046 p
= strchr(p
, '\n');
1056 * Parses a stack frame including its frame number
1059 parseFrame(const char *&s
, int &frameNo
, QString
& func
,
1060 QString
& file
, int &lineNo
, DbgAddr
& address
)
1063 // TRACE("XsldbgDriver ::parseFrame");
1064 /* skip leading 'where' or 'frame <frame_no>' */
1065 if ((strncmp(s
, "where", 5) == 0) || (strncmp(s
, "frame", 5) == 0)) {
1066 s
= strchr(s
, '\n');
1067 if ((*s
!= '\0') && (*s
!= '#'))
1073 //#1 template :"/" in file /home/keith/anon_CVS/xsldbg/docs/en/xsldoc.xsl : line 21
1074 // must start with a hash mark followed by number
1075 if (s
[0] != '#' || !isdigit(s
[1]))
1078 //TRACE("XsldbgDriver ::parseFrame got #");
1079 s
++; /* skip the hash mark */
1085 //TRACE(QString("Got frame ").append(QString::number(frameNo)));
1089 parseFrameInfo(s
, func
, file
, lineNo
, address
);
1090 // TRACE("Will next look at ");
1096 XsldbgDriver::parseBackTrace(const char *output
,
1097 QList
< StackFrame
> &stack
)
1100 int lineNo
, frameNo
;
1103 while (::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
)) {
1104 StackFrame
*frm
= new StackFrame
;
1106 frm
->frameNo
= frameNo
;
1107 frm
->fileName
= file
;
1108 frm
->lineNo
= lineNo
;
1109 frm
->address
= address
;
1110 frm
->var
= new VarTree(func
, VarTree::NKplain
);
1116 XsldbgDriver::parseFrameChange(const char *output
, int &frameNo
,
1117 QString
& file
, int &lineNo
,
1122 return::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
);
1127 XsldbgDriver::parseBreakList(const char *output
,
1128 QList
< Breakpoint
> &brks
)
1130 TRACE("parseBreakList");
1131 /* skip the first blank line */
1135 QString location
, file
, lineNo
;
1137 QString templateName
;
1140 uint ignoreCount
= 0;
1143 p
= strchr(output
, '\n');/* skip the first blank line*/
1145 while ((p
!= 0) && (*p
!= '\0')) {
1148 templateName
= QString();
1149 Breakpoint::Type bpType
= Breakpoint::breakpoint
;
1150 //qDebug("Looking at :%s", p);
1151 if (strncmp(p
, " Breakpoint", 11) != 0)
1159 long bpNum
= strtol(p
, &dummy
, 10); /* don't care about overflows */
1162 if ((p
== 0) || (p
[1] == '\0'))
1167 // Get breakpoint state ie enabled/disabled
1168 if (strncmp(p
, "enabled", 7) == 0) {
1172 if (strncmp(p
, "disabled", 8) == 0) {
1176 TRACE("Parse error in breakpoint list");
1182 //TRACE("Looking for template");
1184 if (strncmp(p
, " for template: \"", 16) == 0){
1186 //TRACE("Looking for template name near");
1188 /* get the template name */
1189 while (p
&& (*p
!= '\0') && (*p
!= '\"')){
1190 templateName
.append(*p
);
1196 TRACE("Error missed \" near");
1201 //TRACE("Looking for mode near");
1203 if (strncmp(p
, " mode: \"", 8) == 0){
1205 while (p
&& *p
!= '\"')
1211 if (strncmp(p
, " in file ", 9) != 0){
1212 TRACE("Parse error in breakpoint list");
1218 /* skip ' in file ' */
1224 /* grab file name */
1225 while ((*p
!= '\"') && !isspace(*p
)) {
1234 /* skip ' : line ' */
1236 while (isspace(*p
)) {
1240 while (isdigit(*p
)) {
1247 Breakpoint
*bp
= new Breakpoint
;
1249 // take 1 of line number
1250 lineNo
.setNum(lineNo
.toInt() -1);
1253 bp
->temporary
= false;
1254 bp
->enabled
= enabled
;
1255 location
.append("in ").append(templateName
).append(" at ");
1256 location
.append(file
).append(":").append(lineNo
);
1257 bp
->location
= location
;
1258 bp
->fileName
= file
;
1259 bp
->lineNo
= lineNo
.toInt();
1260 bp
->address
= address
;
1261 bp
->hitCount
= hits
;
1262 bp
->ignoreCount
= ignoreCount
;
1263 bp
->condition
= condition
;
1269 TRACE("Outof memory, breakpoint not created");
1272 p
= strchr(p
, '\n');
1281 XsldbgDriver::parseThreadList(const char */
*output*/
,
1282 QList
< ThreadInfo
> &/*threads*/)
1288 XsldbgDriver::parseBreakpoint(const char *output
, int &id
,
1289 QString
&file
, int &lineNo
, QString
&address
)
1292 if ( strncmp(output
, "Error:", 6) == 0) {
1297 if (strncmp(output
, "Breakpoint ", 11) != 0)
1301 if (!isdigit(*output
))
1305 id
= strtol(output
, &dummy
, 10); /* don't care about overflows */
1306 if (output
== dummy
)
1309 // the file name + lineNo will be filled in later from the breakpoint list
1310 file
= address
= QString();
1316 XsldbgDriver::parseLocals(const char *output
, QList
< VarTree
> &newVars
)
1319 /* keep going until error or xsldbg prompt is found */
1320 while (*output
!= '\0') {
1321 VarTree
*variable
= parseVar(output
);
1323 if (variable
== 0) {
1326 // do not add duplicates
1327 for (VarTree
* o
= newVars
.first(); o
!= 0; o
= newVars
.next()) {
1328 if (o
->getText() == variable
->getText()) {
1334 newVars
.append(variable
);
1341 XsldbgDriver::parsePrintExpr(const char *output
, bool wantErrorValue
,
1344 // check for error conditions
1345 if (parseErrorMessage(output
, var
, wantErrorValue
)) {
1348 // parse the variable
1349 var
= parseVar(output
);
1355 XsldbgDriver::parseChangeWD(const char *output
, QString
& message
)
1357 bool isGood
= false;
1359 if (strncmp(output
, "Change to directory", 20) == 0) {
1360 output
= output
+ 20; /* skip 'Change to directory' */
1361 message
= QString(output
).simplifyWhiteSpace();
1362 if (message
.isEmpty()) {
1363 message
= i18n("New working directory: ") + m_programWD
;
1371 XsldbgDriver::parseChangeExecutable(const char *output
, QString
& message
)
1374 TRACE(QString("XsldbgDriver::parseChangeExecutable :") + output
);
1375 m_haveCoreFile
= false;
1378 * The command is successful if there is no output or the single
1379 * message (no debugging symbols found)...
1381 QRegExp
exp(".*Load of source deferred. Use the run command.*");
1382 int len
, index
= exp
.match(output
, 0, &len
);
1385 TRACE("Parsed stylesheet executable");
1388 return (output
[0] == '\0') || (index
!= -1);
1392 XsldbgDriver::parseCoreFile(const char *output
)
1394 TRACE("XsldbgDriver::parseCoreFile");
1396 QRegExp
exp(".*Load of data file deferred. Use the run command.*");
1397 int len
, index
= exp
.match(output
, 0, &len
);
1400 m_haveCoreFile
= true;
1401 TRACE("Parsed data file name");
1404 return m_haveCoreFile
;
1408 XsldbgDriver::parseProgramStopped(const char *output
, QString
& message
)
1410 /* Not sure about this function leave it here for the moment */
1412 * return DebuggerDriver::SFrefreshBreak & DebuggerDriver::SFprogramActive;
1415 // go through the output, line by line, checking what we have
1416 const char *start
= output
- 1;
1417 uint flags
= SFprogramActive
;
1419 message
= QString();
1421 start
++; /* skip '\n' */
1423 if (strncmp(start
, "Finished stylesheet\n\032\032\n", 21) == 0){
1424 // flags &= ~SFprogramActive;
1428 // next line, please
1429 start
= strchr(start
, '\n');
1430 } while (start
!= 0);
1436 XsldbgDriver::parseSharedLibs(const char */
*output*/
, QStrList
& /*shlibs*/)
1442 XsldbgDriver::parseFindType(const char */
*output*/
, QString
& /*type*/)
1448 XsldbgDriver::parseRegisters(const char */
*output*/
,
1449 QList
< RegisterInfo
> &/*regs*/)
1455 XsldbgDriver::parseInfoLine(const char */
*output*/
, QString
& /*addrFrom*/,
1456 QString
& /*addrTo*/)
1462 XsldbgDriver::parseDisassemble(const char */
*output*/
,
1463 QList
< DisassembledCode
> &/*code*/)
1469 XsldbgDriver::parseMemoryDump(const char */
*output*/
,
1470 QList
< MemoryDump
> &/*memdump*/)
1472 return i18n("No memory dump available");
1476 XsldbgDriver::parseSetVariable(const char */
*output*/
)
1483 #include "xsldbgdriver.moc"