2 * Copyright Johannes Sixt, Keith Isdale
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
7 #include "xsldbgdriver.h"
11 #include <QStringList>
12 #include <klocale.h> /* i18n */
15 #include <stdlib.h> /* strtol, atoi */
16 #include <string.h> /* strcpy */
17 #include <kmessagebox.h>
23 static ExprValue
*parseVar(const char *&s
);
24 static bool parseName(const char *&s
, QString
& name
,
25 VarTree::NameKind
& kind
);
26 static bool parseValue(const char *&s
, ExprValue
* variable
);
27 static bool isErrorExpr(const char *output
);
29 #define TERM_IO_ALLOWED 1
31 // TODO: make this cmd info stuff non-static to allow multiple
32 // simultaneous gdbs to run!
34 struct XsldbgCmdInfo
{
36 const char *fmt
; /* format string */
38 argNone
, argString
, argNum
,
39 argStringNum
, argNumString
,
45 * The following array of commands must be sorted by the DC* values,
46 * because they are used as indices.
48 static XsldbgCmdInfo cmds
[] = {
49 {DCinitialize
, "init\n", XsldbgCmdInfo::argNone
},
50 {DCtty
, "tty %s\n", XsldbgCmdInfo::argString
},
51 {DCexecutable
, "source %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
52 {DCtargetremote
, "print 'target remote %s'\n", XsldbgCmdInfo::argString
},
53 {DCcorefile
, "data %s\n", XsldbgCmdInfo::argString
}, /* force a restart */
54 {DCattach
, "print 'attach %s'\n", XsldbgCmdInfo::argString
},
55 {DCinfolinemain
, "print 'info main line'\n", XsldbgCmdInfo::argNone
},
56 {DCinfolocals
, "locals -f\n", XsldbgCmdInfo::argNone
},
57 {DCinforegisters
, "print 'info reg'\n", XsldbgCmdInfo::argNone
},
58 {DCexamine
, "print 'x %s %s'\n", XsldbgCmdInfo::argString2
},
59 {DCinfoline
, "print 'templates %s:%d'\n", XsldbgCmdInfo::argStringNum
},
60 {DCdisassemble
, "print 'disassemble %s %s'\n", XsldbgCmdInfo::argString2
},
61 {DCsetargs
, "data %s\n", XsldbgCmdInfo::argString
},
62 {DCsetenv
, "addparam %s %s\n", XsldbgCmdInfo::argString2
},
63 {DCunsetenv
, "unset env %s\n", XsldbgCmdInfo::argString
},
64 {DCsetoption
, "setoption %s %d\n", XsldbgCmdInfo::argStringNum
},
65 {DCcd
, "chdir %s\n", XsldbgCmdInfo::argString
},
66 {DCbt
, "where\n", XsldbgCmdInfo::argNone
},
67 {DCrun
, "run\nsource\n", XsldbgCmdInfo::argNone
}, /* Ensure that at the start
68 of executing XSLT we show the XSLT file */
69 {DCcont
, "continue\n", XsldbgCmdInfo::argNone
},
70 {DCstep
, "step\n", XsldbgCmdInfo::argNone
},
71 {DCstepi
, "step\n", XsldbgCmdInfo::argNone
},
72 {DCnext
, "next\n", XsldbgCmdInfo::argNone
},
73 {DCnexti
, "next\n", XsldbgCmdInfo::argNone
},
74 {DCfinish
, "stepup\n", XsldbgCmdInfo::argNone
},
75 {DCuntil
, "continue %s:%d\n", XsldbgCmdInfo::argStringNum
},
76 {DCkill
, "quit\n", XsldbgCmdInfo::argNone
},
77 {DCbreaktext
, "break %s\n", XsldbgCmdInfo::argString
},
78 {DCbreakline
, "break -l %s %d\n", XsldbgCmdInfo::argStringNum
},
79 {DCtbreakline
, "break -l %s %d\n", XsldbgCmdInfo::argStringNum
},
80 {DCbreakaddr
, "print `break *%s`\n", XsldbgCmdInfo::argString
},
81 {DCtbreakaddr
, "print `tbreak *%s`\n", XsldbgCmdInfo::argString
},
82 {DCwatchpoint
, "print 'watch %s'\n", XsldbgCmdInfo::argString
},
83 {DCdelete
, "delete %d\n", XsldbgCmdInfo::argNum
},
84 {DCenable
, "enable %d\n", XsldbgCmdInfo::argNum
},
85 {DCdisable
, "disable %d\n", XsldbgCmdInfo::argNum
},
86 {DCprint
, "print %s\n", XsldbgCmdInfo::argString
},
87 {DCprintDeref
, "print 'print (*%s)'\n", XsldbgCmdInfo::argString
},
88 {DCprintStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
89 {DCprintQStringStruct
, "print 'print %s'\n", XsldbgCmdInfo::argString
},
90 {DCframe
, "frame %d\n", XsldbgCmdInfo::argNum
},
91 {DCfindType
, "print 'whatis %s'\n", XsldbgCmdInfo::argString
},
92 {DCinfosharedlib
, "stylesheets\n", XsldbgCmdInfo::argNone
},
93 {DCthread
, "print 'thread %d'\n", XsldbgCmdInfo::argNum
},
94 {DCinfothreads
, "print 'info threads'\n", XsldbgCmdInfo::argNone
},
95 {DCinfobreak
, "show\n", XsldbgCmdInfo::argNone
},
96 {DCcondition
, "print 'condition %d %s'\n", XsldbgCmdInfo::argNumString
},
97 {DCsetpc
, "print 'set variable $pc=%s'\n", XsldbgCmdInfo::argString
},
98 {DCignore
, "print 'ignore %d %d'\n", XsldbgCmdInfo::argNum2
},
99 {DCprintWChar
, "print 'ignore %s'\n", XsldbgCmdInfo::argString
},
100 {DCsetvariable
, "set %s %s\n", XsldbgCmdInfo::argString2
},
103 #define NUM_CMDS (int(sizeof(cmds)/sizeof(cmds[0])))
104 #define MAX_FMTLEN 200
106 XsldbgDriver::XsldbgDriver():
109 m_haveDataFile
= FALSE
;
112 // check command info array
115 for (int i
= 0; i
< NUM_CMDS
; i
++) {
116 // must be indexable by DbgCommand values, i.e. sorted by DbgCommand values
117 assert(i
== cmds
[i
].cmd
);
118 // a format string must be associated
119 assert(cmds
[i
].fmt
!= 0);
120 assert(strlen(cmds
[i
].fmt
) <= MAX_FMTLEN
);
121 // format string must match arg specification
122 switch (cmds
[i
].argsNeeded
) {
123 case XsldbgCmdInfo::argNone
:
124 assert(strchr(cmds
[i
].fmt
, '%') == 0);
126 case XsldbgCmdInfo::argString
:
127 perc
= strchr(cmds
[i
].fmt
, '%');
128 assert(perc
!= 0 && perc
[1] == 's');
129 assert(strchr(perc
+ 2, '%') == 0);
131 case XsldbgCmdInfo::argNum
:
132 perc
= strchr(cmds
[i
].fmt
, '%');
133 assert(perc
!= 0 && perc
[1] == 'd');
134 assert(strchr(perc
+ 2, '%') == 0);
136 case XsldbgCmdInfo::argStringNum
:
137 perc
= strchr(cmds
[i
].fmt
, '%');
138 assert(perc
!= 0 && perc
[1] == 's');
139 perc
= strchr(perc
+ 2, '%');
140 assert(perc
!= 0 && perc
[1] == 'd');
141 assert(strchr(perc
+ 2, '%') == 0);
143 case XsldbgCmdInfo::argNumString
:
144 perc
= strchr(cmds
[i
].fmt
, '%');
145 assert(perc
!= 0 && perc
[1] == 'd');
146 perc
= strchr(perc
+ 2, '%');
147 assert(perc
!= 0 && perc
[1] == 's');
148 assert(strchr(perc
+ 2, '%') == 0);
150 case XsldbgCmdInfo::argString2
:
151 perc
= strchr(cmds
[i
].fmt
, '%');
152 assert(perc
!= 0 && perc
[1] == 's');
153 perc
= strchr(perc
+ 2, '%');
154 assert(perc
!= 0 && perc
[1] == 's');
155 assert(strchr(perc
+ 2, '%') == 0);
157 case XsldbgCmdInfo::argNum2
:
158 perc
= strchr(cmds
[i
].fmt
, '%');
159 assert(perc
!= 0 && perc
[1] == 'd');
160 perc
= strchr(perc
+ 2, '%');
161 assert(perc
!= 0 && perc
[1] == 'd');
162 assert(strchr(perc
+ 2, '%') == 0);
169 XsldbgDriver::~XsldbgDriver()
175 XsldbgDriver::driverName() const
181 XsldbgDriver::defaultXsldbg()
183 return "xsldbg --lang en --shell --gdb";
187 XsldbgDriver::defaultInvocation() const
189 return defaultXsldbg();
192 QStringList
XsldbgDriver::boolOptionList() const
194 QStringList allOptions
;
195 allOptions
.append("verbose");
196 allOptions
.append("repeat");
197 allOptions
.append("debug");
198 allOptions
.append("novalid");
199 allOptions
.append("noout");
200 allOptions
.append("html");
201 allOptions
.append("docbook");
202 allOptions
.append("nonet");
203 allOptions
.append("catalogs");
204 allOptions
.append("xinclude");
205 allOptions
.append("profile");
210 XsldbgDriver::startup(QString cmdStr
)
212 if (!DebuggerDriver::startup(cmdStr
))
215 static const char xsldbgInitialize
[] = "pwd\nsetoption gdb 2\n"; /* don't need to do anything else */
217 executeCmdString(DCinitialize
, xsldbgInitialize
, false);
223 XsldbgDriver::commandFinished(CmdQueueItem
* cmd
)
226 TRACE(__PRETTY_FUNCTION__
);
227 // command string must be committed
228 if (!cmd
->m_committed
) {
231 (__PRETTY_FUNCTION__
+
232 (" with uncommited command:\n\t" + cmd
->m_cmdString
)));
236 /* ok, the command is ready */
237 emit
commandReceived(cmd
, m_output
.constData());
239 switch (cmd
->m_cmd
) {
247 if (!::isErrorExpr(m_output
.constData()))
250 // This only shows an error for DCinfolocals
251 // need to update KDebugger::handleRunCommand ?
252 KMessageBox::sorry(0L, m_output
);
258 if (!m_xslFile
.isEmpty())
259 emit
activateFileLine(m_xslFile
, 0, DbgAddr());
267 XsldbgDriver::findPrompt(const QByteArray
& output
) const
270 * If there's a prompt string in the collected output, it must be at
271 * the very end. We do a quick check whether the last characters of
272 * output are suitable and do the full search only if they are.
274 int len
= output
.length();
275 if (len
< 11 || output
[len
-1] != ' ' || output
[len
-2] != '>')
278 // There can be text between "(xsldbg) " and the "> " at the end
279 // since we do not know what that text is, we accept the former
280 // anywhere in the output.
281 return output
.indexOf("(xsldbg) ");
285 XsldbgDriver::parseMarker()
287 char *p
= m_output
.data();
290 if ((p
== 0) || (*p
== '\0')) {
294 if (strncmp(p
, "Breakpoint for file ", 20) == 0)
296 // try to marker on next line !
298 if ((p
!= 0) && (*p
!= '\0'))
303 // extract the marker
304 char *startMarker
= p
+ 20;
306 //TRACE(QString("found marker:") + startMarker);
307 char *endMarker
= strchr(startMarker
, '\n');
314 // extract filename and line number
315 static QRegExp
MarkerRE(" at line (\\d+)");
317 int lineNoStart
= MarkerRE
.indexIn(startMarker
);
319 if (lineNoStart
>= 0) {
320 int lineNo
= MarkerRE
.cap(1).toInt();
324 // now show the window
325 startMarker
[lineNoStart
-1] = '\0'; /* split off file name */
326 TRACE("Got file and line number");
328 TRACE(QString(startMarker
) + ": " + QString::number(lineNo
));
329 emit
activateFileLine(startMarker
, lineNo
- 1, address
);
335 * Escapes characters that might lead to problems when they appear on gdb's
339 normalizeStringArg(QString
& arg
)
342 * Remove trailing backslashes. This approach is a little simplistic,
343 * but we know that there is at the moment no case where a trailing
344 * backslash would make sense.
346 while (!arg
.isEmpty() && arg
[arg
.length() - 1] == '\\') {
347 arg
= arg
.left(arg
.length() - 1);
353 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
)
355 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
356 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString
);
358 normalizeStringArg(strArg
);
361 // need the working directory when parsing the output
362 m_programWD
= strArg
;
363 } else if (cmd
== DCexecutable
) {
364 // want to display the XSL file
369 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.toUtf8().constData());
374 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg
)
376 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
377 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum
);
380 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
);
385 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg
, int intArg
)
387 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
388 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
||
389 cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNumString
||
390 cmd
== DCexamine
|| cmd
== DCtty
);
392 normalizeStringArg(strArg
);
398 * intArg specifies which channels should be redirected to
399 * /dev/null. It is a value or'ed together from RDNstdin,
400 * RDNstdout, RDNstderr.
402 static const char *const runRedir
[8] = {
406 " </dev/null >/dev/null",
408 " </dev/null 2>/dev/null",
410 " </dev/null >/dev/null 2>&1"
413 if (strArg
.isEmpty())
414 intArg
= 7; /* failsafe if no tty */
415 m_redirect
= runRedir
[intArg
& 7];
417 return makeCmdString(DCtty
, strArg
); /* note: no problem if strArg empty */
420 if (cmd
== DCexamine
) {
421 // make a format specifier from the intArg
422 static const char size
[16] = {
423 '\0', 'b', 'h', 'w', 'g'
425 static const char format
[16] = {
426 '\0', 'x', 'd', 'u', 'o', 't',
427 'a', 'c', 'f', 's', 'i'
430 assert(MDTsizemask
== 0xf); /* lowest 4 bits */
431 assert(MDTformatmask
== 0xf0); /* next 4 bits */
432 int count
= 16; /* number of entities to print */
433 char sizeSpec
= size
[intArg
& MDTsizemask
];
434 char formatSpec
= format
[(intArg
& MDTformatmask
) >> 4];
436 assert(sizeSpec
!= '\0');
437 assert(formatSpec
!= '\0');
438 // adjust count such that 16 lines are printed
439 switch (intArg
& MDTformatmask
) {
442 break; /* no modification needed */
444 // all cases drop through:
445 switch (intArg
& MDTsizemask
) {
458 spec
.sprintf("/%d%c%c", count
, sizeSpec
, formatSpec
);
460 return makeCmdString(DCexamine
, spec
, strArg
);
463 if (cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argStringNum
) {
464 // line numbers are zero-based
465 if (cmd
== DCuntil
|| cmd
== DCbreakline
||
466 cmd
== DCtbreakline
|| cmd
== DCinfoline
) {
469 if (cmd
== DCinfoline
) {
470 // must split off file name part
471 strArg
= QFileInfo(strArg
).fileName();
473 cmdString
.sprintf(cmds
[cmd
].fmt
, strArg
.toUtf8().constData(), intArg
);
475 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg
, strArg
.toUtf8().constData());
481 XsldbgDriver::makeCmdString(DbgCommand cmd
, QString strArg1
,
484 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
485 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argString2
);
487 normalizeStringArg(strArg1
);
488 normalizeStringArg(strArg2
);
491 cmdString
.sprintf(cmds
[cmd
].fmt
,
492 strArg1
.toUtf8().constData(),
493 strArg2
.toUtf8().constData());
498 XsldbgDriver::makeCmdString(DbgCommand cmd
, int intArg1
, int intArg2
)
500 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
501 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNum2
);
504 cmdString
.sprintf(cmds
[cmd
].fmt
, intArg1
, intArg2
);
509 XsldbgDriver::executeCmd(DbgCommand cmd
, bool clearLow
)
511 assert(cmd
>= 0 && cmd
< NUM_CMDS
);
512 assert(cmds
[cmd
].argsNeeded
== XsldbgCmdInfo::argNone
);
515 m_haveCoreFile
= false;
518 return executeCmdString(cmd
, cmds
[cmd
].fmt
, clearLow
);
522 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, bool clearLow
)
524 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
), clearLow
);
528 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg
, bool clearLow
)
531 return executeCmdString(cmd
, makeCmdString(cmd
, intArg
), clearLow
);
535 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg
, int intArg
,
538 return executeCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
),
543 XsldbgDriver::executeCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
546 return executeCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
),
551 XsldbgDriver::executeCmd(DbgCommand cmd
, int intArg1
, int intArg2
,
554 return executeCmdString(cmd
, makeCmdString(cmd
, intArg1
, intArg2
),
559 XsldbgDriver::queueCmd(DbgCommand cmd
, QueueMode mode
)
561 return queueCmdString(cmd
, cmds
[cmd
].fmt
, mode
);
565 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, QueueMode mode
)
567 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
), mode
);
571 XsldbgDriver::queueCmd(DbgCommand cmd
, int intArg
, QueueMode mode
)
573 return queueCmdString(cmd
, makeCmdString(cmd
, intArg
), mode
);
577 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg
, int intArg
,
580 return queueCmdString(cmd
, makeCmdString(cmd
, strArg
, intArg
), mode
);
584 XsldbgDriver::queueCmd(DbgCommand cmd
, QString strArg1
, QString strArg2
,
587 return queueCmdString(cmd
, makeCmdString(cmd
, strArg1
, strArg2
), mode
);
591 XsldbgDriver::terminate()
593 qDebug("XsldbgDriver::Terminate");
595 executeCmdString(DCinitialize
, "quit\n", true);
596 ::kill(pid(), SIGTERM
);
601 XsldbgDriver::detachAndTerminate()
603 qDebug("XsldbgDriver::detachAndTerminate");
605 executeCmdString(DCinitialize
, "quit\n", true);
606 ::kill(pid(), SIGINT
);
610 XsldbgDriver::interruptInferior()
612 // remove accidentally queued commands
613 qDebug("interruptInferior");
615 ::kill(pid(), SIGINT
);
619 isErrorExpr(const char *output
)
623 #define ERROR_WORD_COUNT 6
624 static const char *errorWords
[ERROR_WORD_COUNT
] = {
626 "error:", // libxslt error
629 "warning:", // libxslt warning
630 "Information:" // xsldbg information
632 static int errorWordLength
[ERROR_WORD_COUNT
] = {
635 15, /* Unknown command*/
641 for (wordIndex
= 0; wordIndex
< ERROR_WORD_COUNT
; wordIndex
++){
642 // ignore any warnings relating to local variables not being available
644 errorWords
[wordIndex
],
645 errorWordLength
[wordIndex
]) == 0 &&
646 (wordIndex
== 0 && strstr(output
, "try stepping past the xsl:param") == 0) ) {
648 TRACE(QString("Error/Warning/Information from xsldbg ") + output
);
657 * Returns true if the output is an error message. If wantErrorValue is
658 * true, a new ExprValue object is created and filled with the error message.
661 parseErrorMessage(const char *output
,
662 ExprValue
* &variable
, bool wantErrorValue
)
664 if (isErrorExpr(output
)) {
665 if (wantErrorValue
) {
666 // put the error message as value in the variable
667 variable
= new ExprValue(QString(), VarTree::NKplain
);
668 const char *endMsg
= strchr(output
, '\n');
671 endMsg
= output
+ strlen(output
);
672 variable
->m_value
= QString::fromLatin1(output
, endMsg
- output
);
683 XsldbgDriver::setPrintQStringDataCmd(const char* /*cmd*/)
688 XsldbgDriver::parseQCharArray(const char */
*output*/
, bool /*wantErrorValue*/,
691 ExprValue
*variable
= 0;
693 TRACE("XsldbgDriver::parseQCharArray not implmented");
698 parseVar(const char *&s
)
701 ExprValue
*variable
= 0L;
704 VarTree::NameKind kind
;
706 TRACE(__PRETTY_FUNCTION__
);
709 if (parseErrorMessage(p
, variable
, false) == true) {
710 TRACE("Found error message");
714 if (strncmp(p
, " Local", 6) == 0) {
717 TRACE("Found local variable");
718 } else if (strncmp(p
, " Global", 7) == 0) {
721 TRACE("Found global variable");
722 } else if (strncmp(p
, "= ", 2) == 0) {
723 /* we're processing the result of a "print command" */
725 const char *nextLine
= strchr(p
, '\n');
727 TRACE("Found print expr");
729 p
= p
+ 2; /* skip the "= " */
730 name
= QString::fromLatin1(p
, nextLine
- p
);
731 kind
= VarTree::NKplain
;
733 variable
= new ExprValue(name
, kind
);
734 variable
->m_varKind
= VarTree::VKsimple
;
735 parseValue(p
, variable
);
739 return variable
; /* don't know what to do this this data abort!! */
746 // No value provided just a name
747 TRACE(QString("Parse var: name") + p
);
748 if (!parseName(p
, name
, kind
)) {
751 variable
= new ExprValue(name
, kind
);
752 if (variable
!= 0L) {
753 variable
->m_varKind
= VarTree::VKsimple
;
760 TRACE(QString("Parse var: name") + p
);
761 if (!parseName(p
, name
, kind
)) {
764 variable
= new ExprValue(name
, kind
);
765 if (variable
!= 0L) {
766 variable
->m_varKind
= VarTree::VKsimple
;
770 if (!parseValue(p
, variable
)) {
785 skipName(const char *&p
)
787 // allow : (for enumeration values) and $ and . (for _vtbl.)
788 while (isalnum(*p
) || *p
== '_' || *p
== ':' || *p
== '$' || *p
== '.')
793 parseName(const char *&s
, QString
& name
, VarTree::NameKind
& kind
)
795 /* qDebug(__PRETTY_FUNCTION__); */
796 kind
= VarTree::NKplain
;
801 // examples of names:
804 while ((*p
!= '\n') && (*p
!= '\0')) {
810 name
= QString::fromLatin1(s
, len
);
811 /* XSL variables will have a $ prefix to be evaluated
813 //TRACE(QString("parseName got name" ) + name);
815 // return the new position
821 parseValue(const char *&s
, ExprValue
* variable
)
823 const char *start
= s
, *end
= s
;
824 ExprValue
* childValue
;
825 #define VALUE_END_MARKER_INDEX 0
827 /* This mark the end of a value */
828 static const char *marker
[] = {
829 "\032\032", /* value end marker*/
831 "Breakpoint at", /* stepped to next location */
832 "Breakpoint in", /* reached a set breakpoint */
833 "Reached ", /* reached template */
841 static char valueBuffer
[2048];
842 int markerIndex
= 0, foundEnd
= 0;
846 return false; /* should never happen but .. */
848 while (start
&& (*start
!= '\0')) {
849 /* look for the next marker */
850 for (markerIndex
= 0; marker
[markerIndex
] != 0; markerIndex
++) {
852 strncmp(start
, marker
[markerIndex
],
853 strlen(marker
[markerIndex
])) == 0;
862 end
= strchr(start
, '\n');
864 copySize
= end
- start
;
866 copySize
= strlen(start
);
867 if (copySize
>= sizeof(valueBuffer
))
868 copySize
= sizeof(valueBuffer
)-1;
870 strncpy(valueBuffer
, start
, copySize
);
871 valueBuffer
[copySize
] = '\0';
872 TRACE("Got value :");
874 if ((variable
->m_varKind
== VarTree::VKsimple
)) {
875 if (!variable
->m_value
.isEmpty()){
876 variable
->m_varKind
= VarTree::VKarray
;
877 childValue
= new ExprValue(variable
->m_value
, VarTree::NKplain
);
878 variable
->appendChild(childValue
);
879 childValue
= new ExprValue(valueBuffer
, VarTree::NKplain
);
880 variable
->appendChild(childValue
);
881 variable
->m_value
= "";
883 variable
->m_value
= valueBuffer
;
886 childValue
= new ExprValue(valueBuffer
, VarTree::NKplain
);
887 variable
->appendChild(childValue
);
899 TRACE(QString("Unable to find end on value near :") + start
);
901 // If we've got something otherthan a end of value marker then
902 // advance to the end of this buffer
903 if (markerIndex
!= VALUE_END_MARKER_INDEX
){
904 while (start
&& *start
!= '\0')
907 start
= start
+ strlen(marker
[0]);
917 * Parses a stack frame.
920 parseFrameInfo(const char *&s
, QString
& func
,
921 QString
& file
, int &lineNo
, DbgAddr
& /*address*/)
923 const char *p
= s
, *endPos
= s
+ strlen(s
);
924 QString lineNoString
;
926 TRACE("parseFrameInfo");
930 /* skip 'template :\" */
934 while ((*p
!= '\"') && (*p
!= '\0')) {
938 while ((*p
!= '\0') && *p
!= '"')
948 /* skip mode :".*" */
949 while ((*p
!= '\0') && *p
!= '"')
953 while ((*p
!= '\0') && *p
!= '"')
956 /* skip '" in file ' */
962 while (!isspace(*p
) && (*p
!= '\"') && (*p
!= '\0')) {
975 /* skip ' : line '" */
985 /* KDbg uses an offset of +1 for its line numbers */
986 lineNo
= atoi(p
) - 1;
987 lineNoString
= QString::number(lineNo
);
989 /* convert func into format needed */
993 func
.append(lineNoString
);
995 /*advance to next line */
1006 * Parses a stack frame including its frame number
1009 parseFrame(const char *&s
, int &frameNo
, QString
& func
,
1010 QString
& file
, int &lineNo
, DbgAddr
& address
)
1013 // TRACE("XsldbgDriver ::parseFrame");
1014 /* skip leading 'where' or 'frame <frame_no>' */
1015 if ((strncmp(s
, "where", 5) == 0) || (strncmp(s
, "frame", 5) == 0)) {
1016 s
= strchr(s
, '\n');
1017 if ((*s
!= '\0') && (*s
!= '#'))
1023 //#1 template :"/" in file /home/keith/anon_CVS/xsldbg/docs/en/xsldoc.xsl : line 21
1024 // must start with a hash mark followed by number
1025 if (s
[0] != '#' || !isdigit(s
[1]))
1028 //TRACE("XsldbgDriver ::parseFrame got #");
1029 s
++; /* skip the hash mark */
1035 //TRACE(QString("Got frame ").append(QString::number(frameNo)));
1039 parseFrameInfo(s
, func
, file
, lineNo
, address
);
1040 // TRACE("Will next look at ");
1046 XsldbgDriver::parseBackTrace(const char *output
,
1047 std::list
< StackFrame
> &stack
)
1050 int lineNo
, frameNo
;
1053 while (::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
)) {
1054 stack
.push_back(StackFrame());
1055 StackFrame
* frm
= &stack
.back();
1057 frm
->frameNo
= frameNo
;
1058 frm
->fileName
= file
;
1059 frm
->lineNo
= lineNo
;
1060 frm
->address
= address
;
1061 frm
->var
= new ExprValue(func
, VarTree::NKplain
);
1066 XsldbgDriver::parseFrameChange(const char *output
, int &frameNo
,
1067 QString
& file
, int &lineNo
,
1072 return::parseFrame(output
, frameNo
, func
, file
, lineNo
, address
);
1077 XsldbgDriver::parseBreakList(const char *output
,
1078 std::list
< Breakpoint
> &brks
)
1080 TRACE("parseBreakList");
1081 /* skip the first blank line */
1087 p
= strchr(output
, '\n');/* skip the first blank line*/
1089 while ((p
!= 0) && (*p
!= '\0')) {
1092 QString templateName
;
1093 //qDebug("Looking at :%s", p);
1094 if (strncmp(p
, " Breakpoint", 11) != 0)
1102 bp
.id
= strtol(p
, &dummy
, 10); /* don't care about overflows */
1105 if ((p
== 0) || (p
[1] == '\0'))
1110 // Get breakpoint state ie enabled/disabled
1111 if (strncmp(p
, "enabled", 7) == 0) {
1115 if (strncmp(p
, "disabled", 8) == 0) {
1119 TRACE("Parse error in breakpoint list");
1125 //TRACE("Looking for template");
1127 if (strncmp(p
, " for template: \"", 16) == 0){
1129 //TRACE("Looking for template name near");
1131 /* get the template name */
1132 while (p
&& (*p
!= '\0') && (*p
!= '\"')){
1133 templateName
.append(*p
);
1139 TRACE("Error missed \" near");
1144 //TRACE("Looking for mode near");
1146 if (strncmp(p
, " mode: \"", 8) == 0){
1148 while (p
&& *p
!= '\"')
1154 if (strncmp(p
, " in file ", 9) != 0){
1155 TRACE("Parse error in breakpoint list");
1161 /* skip ' in file ' */
1167 /* grab file name */
1169 while ((*p
!= '\"') && !isspace(*p
)) {
1178 /* skip ' : line ' */
1180 while (isspace(*p
)) {
1185 while (isdigit(*p
)) {
1190 // bp.lineNo is zero-based
1191 bp
.lineNo
= lineNo
.toInt() - 1;
1192 bp
.location
= QString("in %1 at %2:%3").arg(templateName
, file
, lineNo
);
1197 p
= strchr(p
, '\n');
1205 std::list
<ThreadInfo
>
1206 XsldbgDriver::parseThreadList(const char */
*output*/
)
1208 return std::list
<ThreadInfo
>();
1212 XsldbgDriver::parseBreakpoint(const char *output
, int &id
,
1213 QString
&file
, int &lineNo
, QString
&address
)
1216 if ( strncmp(output
, "Error:", 6) == 0) {
1221 if (strncmp(output
, "Breakpoint ", 11) != 0)
1225 if (!isdigit(*output
))
1229 id
= strtol(output
, &dummy
, 10); /* don't care about overflows */
1230 if (output
== dummy
)
1233 // the file name + lineNo will be filled in later from the breakpoint list
1234 file
= address
= QString();
1240 XsldbgDriver::parseLocals(const char *output
, std::list
< ExprValue
* > &newVars
)
1243 /* keep going until error or xsldbg prompt is found */
1244 while (*output
!= '\0') {
1245 ExprValue
*variable
= parseVar(output
);
1247 if (variable
== 0) {
1250 // do not add duplicates
1251 for (std::list
<ExprValue
*>::iterator o
= newVars
.begin(); o
!= newVars
.end(); ++o
) {
1252 if ((*o
)->m_name
== variable
->m_name
) {
1258 newVars
.push_back(variable
);
1265 XsldbgDriver::parsePrintExpr(const char *output
, bool wantErrorValue
)
1268 // check for error conditions
1269 if (!parseErrorMessage(output
, var
, wantErrorValue
)) {
1270 // parse the variable
1271 var
= parseVar(output
);
1277 XsldbgDriver::parseChangeWD(const char *output
, QString
& message
)
1279 bool isGood
= false;
1281 if (strncmp(output
, "Change to directory", 20) == 0) {
1282 output
= output
+ 20; /* skip 'Change to directory' */
1283 message
= QString(output
).simplified();
1284 if (message
.isEmpty()) {
1285 message
= i18n("New working directory: ") + m_programWD
;
1293 XsldbgDriver::parseChangeExecutable(const char *output
, QString
& message
)
1296 TRACE(QString("XsldbgDriver::parseChangeExecutable :") + output
);
1297 m_haveCoreFile
= false;
1299 if (strstr(output
, "Load of source deferred. Use the run command") != 0) {
1300 TRACE("Parsed stylesheet executable");
1301 message
= QString();
1303 return message
.isEmpty();
1307 XsldbgDriver::parseCoreFile(const char *output
)
1309 TRACE("XsldbgDriver::parseCoreFile");
1312 if (strstr(output
, "Load of data file deferred. Use the run command") != 0) {
1313 m_haveCoreFile
= true;
1314 TRACE("Parsed data file name");
1317 return m_haveCoreFile
;
1321 XsldbgDriver::parseProgramStopped(const char *output
, QString
& message
)
1323 /* Not sure about this function leave it here for the moment */
1325 * return DebuggerDriver::SFrefreshBreak & DebuggerDriver::SFprogramActive;
1328 // go through the output, line by line, checking what we have
1329 const char *start
= output
- 1;
1330 uint flags
= SFprogramActive
;
1332 message
= QString();
1334 start
++; /* skip '\n' */
1336 if (strncmp(start
, "Finished stylesheet\n\032\032\n", 21) == 0){
1337 // flags &= ~SFprogramActive;
1341 // next line, please
1342 start
= strchr(start
, '\n');
1343 } while (start
!= 0);
1349 XsldbgDriver::parseSharedLibs(const char */
*output*/
)
1351 return QStringList();
1355 XsldbgDriver::parseFindType(const char */
*output*/
, QString
& /*type*/)
1360 std::list
<RegisterInfo
>
1361 XsldbgDriver::parseRegisters(const char */
*output*/
)
1363 return std::list
<RegisterInfo
>();
1367 XsldbgDriver::parseInfoLine(const char */
*output*/
, QString
& /*addrFrom*/,
1368 QString
& /*addrTo*/)
1373 std::list
<DisassembledCode
>
1374 XsldbgDriver::parseDisassemble(const char */
*output*/
)
1376 return std::list
<DisassembledCode
>();
1380 XsldbgDriver::parseMemoryDump(const char */
*output*/
,
1381 std::list
< MemoryDump
> &/*memdump*/)
1383 return i18n("No memory dump available");
1387 XsldbgDriver::parseSetVariable(const char */
*output*/
)
1394 #include "xsldbgdriver.moc"