1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "scriptdebugger.h"
52#include "scriptbreakpointmanager.h"
53
54#include <QtScript/QScriptEngine>
55#include <QtScript/QScriptEngineAgent>
56#include <QtScript/QScriptContextInfo>
57#include <QtScript/QScriptValueIterator>
58#include <QtCore/QTextStream>
59#include <QtCore/QStack>
60
61static QString safeValueToString(const QScriptValue &value)
62{
63 if (value.isObject())
64 return QLatin1String("[object Object]");
65 else
66 return value.toString();
67}
68
69class ScriptInfo;
70class ScriptBreakpointManager;
71
72class ScriptDebuggerPrivate
73 : public QScriptEngineAgent
74{
75 Q_DECLARE_PUBLIC(ScriptDebugger)
76public:
77 enum Mode {
78 Run,
79 StepInto,
80 StepOver
81 };
82
83 ScriptDebuggerPrivate(QScriptEngine *engine);
84 ~ScriptDebuggerPrivate();
85
86 // QScriptEngineAgent interface
87 void scriptLoad(qint64 id, const QString &program,
88 const QString &fileName, int lineNumber);
89 void scriptUnload(qint64 id);
90
91 void positionChange(qint64 scriptId,
92 int lineNumber, int columnNumber);
93
94 void functionEntry(qint64 scriptId);
95 void functionExit(qint64 scriptId,
96 const QScriptValue &returnValue);
97
98 void exceptionThrow(qint64 scriptId,
99 const QScriptValue &exception, bool hasHandler);
100
101
102 void interactive();
103 bool executeCommand(const QString &command, const QStringList &args);
104
105 void setMode(Mode mode);
106 Mode mode() const;
107
108 int frameCount() const;
109 void setCurrentFrameIndex(int index);
110 int currentFrameIndex() const;
111
112 QScriptContext *frameContext(int index) const;
113 QScriptContext *currentFrameContext() const;
114
115 ScriptInfo *scriptInfo(QScriptContext *context) const;
116
117 int listLineNumber() const;
118 void setListLineNumber(int lineNumber);
119
120 QString readLine();
121 void output(const QString &text);
122 void message(const QString &text);
123 void errorMessage(const QString &text);
124
125 // attributes
126 QTextStream *m_defaultInputStream;
127 QTextStream *m_defaultOutputStream;
128 QTextStream *m_defaultErrorStream;
129 QTextStream *m_inputStream;
130 QTextStream *m_outputStream;
131 QTextStream *m_errorStream;
132
133 ScriptBreakpointManager *m_bpManager;
134 Mode m_mode;
135 QMap<qint64, ScriptInfo*> m_scripts;
136 QMap<QScriptContext*, QStack<qint64> > m_contextProgramIds;
137
138 QString m_lastInteractiveCommand;
139 QString m_commandPrefix;
140 int m_stepDepth;
141 int m_currentFrameIndex;
142 int m_listLineNumber;
143
144 ScriptDebugger *q_ptr;
145};
146
147class ScriptInfo
148{
149public:
150 ScriptInfo(const QString &code, const QString &fileName, int lineNumber)
151 : m_code(code), m_fileName(fileName), m_lineNumber(lineNumber)
152 { }
153
154 inline QString code() const
155 { return m_code; }
156 inline QString fileName() const
157 { return m_fileName; }
158 inline int lineNumber() const
159 { return m_lineNumber; }
160
161 QString lineText(int lineNumber);
162 QMap<int, int> m_lineOffsets;
163
164private:
165 int lineOffset(int lineNumber);
166
167 QString m_code;
168 QString m_fileName;
169 int m_lineNumber;
170};
171
172int ScriptInfo::lineOffset(int lineNumber)
173{
174 QMap<int, int>::const_iterator it = m_lineOffsets.constFind(akey: lineNumber);
175 if (it != m_lineOffsets.constEnd())
176 return it.value();
177
178 int offset;
179 it = m_lineOffsets.constFind(akey: lineNumber - 1);
180 if (it != m_lineOffsets.constEnd()) {
181 offset = it.value();
182 offset = m_code.indexOf(c: QLatin1Char('\n'), from: offset);
183 if (offset != -1)
184 ++offset;
185 m_lineOffsets.insert(akey: lineNumber, avalue: offset);
186 } else {
187 int index;
188 it = m_lineOffsets.lowerBound(akey: lineNumber);
189 if (it != m_lineOffsets.constBegin())
190 --it;
191 if (it != m_lineOffsets.constBegin()) {
192 index = it.key();
193 offset = it.value();
194 } else {
195 index = m_lineNumber;
196 offset = 0;
197 }
198 int j = index;
199 for ( ; j < lineNumber; ++j) {
200 m_lineOffsets.insert(akey: j, avalue: offset);
201 offset = m_code.indexOf(c: QLatin1Char('\n'), from: offset);
202 if (offset == -1)
203 break;
204 ++offset;
205 }
206 m_lineOffsets.insert(akey: j, avalue: offset);
207 }
208 return offset;
209}
210
211QString ScriptInfo::lineText(int lineNumber)
212{
213 int startOffset = lineOffset(lineNumber);
214 if (startOffset == -1)
215 return QString();
216 int endOffset = lineOffset(lineNumber: lineNumber + 1);
217 if (endOffset == -1)
218 return m_code.mid(position: startOffset);
219 else
220 return m_code.mid(position: startOffset, n: endOffset - startOffset - 1);
221}
222
223
224
225ScriptDebuggerPrivate::ScriptDebuggerPrivate(QScriptEngine *engine)
226 : QScriptEngineAgent(engine), m_mode(Run)
227{
228 m_commandPrefix = QLatin1String(".");
229 m_bpManager = new ScriptBreakpointManager;
230 m_defaultInputStream = new QTextStream(stdin);
231 m_defaultOutputStream = new QTextStream(stdout);
232 m_defaultErrorStream = new QTextStream(stderr);
233 m_inputStream = m_defaultInputStream;
234 m_outputStream = m_defaultOutputStream;
235 m_errorStream = m_defaultErrorStream;
236}
237
238ScriptDebuggerPrivate::~ScriptDebuggerPrivate()
239{
240 delete m_defaultInputStream;
241 delete m_defaultOutputStream;
242 delete m_defaultErrorStream;
243 delete m_bpManager;
244 qDeleteAll(c: m_scripts);
245}
246
247QString ScriptDebuggerPrivate::readLine()
248{
249 return m_inputStream->readLine();
250}
251
252void ScriptDebuggerPrivate::output(const QString &text)
253{
254 *m_outputStream << text;
255}
256
257void ScriptDebuggerPrivate::message(const QString &text)
258{
259 *m_outputStream << text << endl;
260 m_outputStream->flush();
261}
262
263void ScriptDebuggerPrivate::errorMessage(const QString &text)
264{
265 *m_errorStream << text << endl;
266 m_errorStream->flush();
267}
268
269void ScriptDebuggerPrivate::setMode(Mode mode)
270{
271 m_mode = mode;
272}
273
274ScriptDebuggerPrivate::Mode ScriptDebuggerPrivate::mode() const
275{
276 return m_mode;
277}
278
279QScriptContext *ScriptDebuggerPrivate::frameContext(int index) const
280{
281 QScriptContext *ctx = engine()->currentContext();
282 for (int i = 0; i < index; ++i) {
283 ctx = ctx->parentContext();
284 if (!ctx)
285 break;
286 }
287 return ctx;
288}
289
290int ScriptDebuggerPrivate::currentFrameIndex() const
291{
292 return m_currentFrameIndex;
293}
294
295void ScriptDebuggerPrivate::setCurrentFrameIndex(int index)
296{
297 m_currentFrameIndex = index;
298 m_listLineNumber = -1;
299}
300
301int ScriptDebuggerPrivate::listLineNumber() const
302{
303 return m_listLineNumber;
304}
305
306void ScriptDebuggerPrivate::setListLineNumber(int lineNumber)
307{
308 m_listLineNumber = lineNumber;
309}
310
311QScriptContext *ScriptDebuggerPrivate::currentFrameContext() const
312{
313 return frameContext(index: currentFrameIndex());
314}
315
316int ScriptDebuggerPrivate::frameCount() const
317{
318 int count = 0;
319 QScriptContext *ctx = engine()->currentContext();
320 while (ctx) {
321 ++count;
322 ctx = ctx->parentContext();
323 }
324 return count;
325}
326
327ScriptInfo *ScriptDebuggerPrivate::scriptInfo(QScriptContext *context) const
328{
329 QStack<qint64> pids = m_contextProgramIds.value(akey: context);
330 if (pids.isEmpty())
331 return 0;
332 return m_scripts.value(akey: pids.top());
333}
334
335void ScriptDebuggerPrivate::interactive()
336{
337 setCurrentFrameIndex(0);
338
339 QString qsdbgPrompt = QString::fromLatin1(str: "(qsdbg) ");
340 QString dotPrompt = QString::fromLatin1(str: ".... ");
341 QString prompt = qsdbgPrompt;
342
343 QString code;
344
345 forever {
346
347 *m_outputStream << prompt;
348 m_outputStream->flush();
349
350 QString line = readLine();
351
352 if (code.isEmpty() && (line.isEmpty() || line.startsWith(s: m_commandPrefix))) {
353 if (line.isEmpty())
354 line = m_lastInteractiveCommand;
355 else
356 m_lastInteractiveCommand = line;
357
358 QStringList parts = line.split(sep: QLatin1Char(' '), behavior: Qt::SkipEmptyParts);
359 if (!parts.isEmpty()) {
360 QString command = parts.takeFirst().mid(position: 1);
361 if (executeCommand(command, args: parts))
362 break;
363 }
364
365 } else {
366 if (line.isEmpty())
367 continue;
368
369 code += line;
370 code += QLatin1Char('\n');
371
372 if (line.trimmed().isEmpty()) {
373 continue;
374
375 } else if (! engine()->canEvaluate(program: code)) {
376 prompt = dotPrompt;
377
378 } else {
379 setMode(Run);
380 QScriptValue result = engine()->evaluate(program: code, fileName: QLatin1String("typein"));
381
382 code.clear();
383 prompt = qsdbgPrompt;
384
385 if (! result.isUndefined()) {
386 errorMessage(text: result.toString());
387 engine()->clearExceptions();
388 }
389 }
390 }
391 }
392}
393
394bool ScriptDebuggerPrivate::executeCommand(const QString &command, const QStringList &args)
395{
396 if (command == QLatin1String("c")
397 || command == QLatin1String("continue")) {
398 setMode(Run);
399 return true;
400 } else if (command == QLatin1String("s")
401 || command == QLatin1String("step")) {
402 setMode(StepInto);
403 return true;
404 } else if (command == QLatin1String("n")
405 || command == QLatin1String("next")) {
406 setMode(StepOver);
407 m_stepDepth = 0;
408 return true;
409 } else if (command == QLatin1String("f")
410 || command == QLatin1String("frame")) {
411 bool ok = false;
412 int index = args.value(i: 0).toInt(ok: &ok);
413 if (ok) {
414 if (index < 0 || index >= frameCount()) {
415 errorMessage(text: "No such frame.");
416 } else {
417 setCurrentFrameIndex(index);
418 QScriptContext *ctx = currentFrameContext();
419 message(text: QString::fromLatin1(str: "#%0 %1").arg(a: index).arg(a: ctx->toString()));
420 }
421 }
422 } else if (command == QLatin1String("bt")
423 || command == QLatin1String("backtrace")) {
424 QScriptContext *ctx = engine()->currentContext();
425 int index = -1;
426 while (ctx) {
427 ++index;
428 QString line = ctx->toString();
429 message(text: QString::fromLatin1(str: "#%0 %1").arg(a: index).arg(a: line));
430 ctx = ctx->parentContext();
431 }
432 } else if (command == QLatin1String("up")) {
433 int index = currentFrameIndex() + 1;
434 if (index == frameCount()) {
435 errorMessage(text: QString::fromLatin1(str: "Initial frame selected; you cannot go up."));
436 } else {
437 setCurrentFrameIndex(index);
438 QScriptContext *ctx = currentFrameContext();
439 message(text: QString::fromLatin1(str: "#%0 %1").arg(a: index).arg(a: ctx->toString()));
440 }
441 } else if (command == QLatin1String("down")) {
442 int index = currentFrameIndex() - 1;
443 if (index < 0) {
444 errorMessage(text: QString::fromLatin1(str: "Bottom (innermost) frame selected; you cannot go down."));
445 } else {
446 setCurrentFrameIndex(index);
447 QScriptContext *ctx = currentFrameContext();
448 message(text: QString::fromLatin1(str: "#%0 %1").arg(a: index).arg(a: ctx->toString()));
449 }
450 } else if (command == QLatin1String("b")
451 || command == QLatin1String("break")) {
452 QString str = args.value(i: 0);
453 int colonIndex = str.indexOf(c: QLatin1Char(':'));
454 if (colonIndex != -1) {
455 // filename:line form
456 QString fileName = str.left(n: colonIndex);
457 int lineNumber = str.mid(position: colonIndex+1).toInt();
458 int id = m_bpManager->setBreakpoint(fileName, lineNumber);
459 message(text: QString::fromLatin1(str: "Breakpoint %0 at %1, line %2.").arg(a: id+1).arg(a: fileName).arg(a: lineNumber));
460 } else {
461 // function
462 QScriptValue fun = engine()->globalObject().property(name: str);
463 if (fun.isFunction()) {
464 int id = m_bpManager->setBreakpoint(fun);
465 message(text: QString::fromLatin1(str: "Breakpoint %0 at %1().").arg(a: id+1).arg(a: str));
466 }
467 }
468 } else if (command == QLatin1String("d")
469 || command == QLatin1String("delete")) {
470 int id = args.value(i: 0).toInt() - 1;
471 m_bpManager->removeBreakpoint(id);
472 } else if (command == QLatin1String("disable")) {
473 int id = args.value(i: 0).toInt() - 1;
474 m_bpManager->setBreakpointEnabled(id, enabled: false);
475 } else if (command == QLatin1String("enable")) {
476 int id = args.value(i: 0).toInt() - 1;
477 m_bpManager->setBreakpointEnabled(id, enabled: true);
478 } else if (command == QLatin1String("list")) {
479 QScriptContext *ctx = currentFrameContext();
480 ScriptInfo *progInfo = scriptInfo(context: ctx);
481 if (!progInfo) {
482 errorMessage(text: "No source text available for this frame.");
483 } else {
484 QScriptContextInfo ctxInfo(ctx);
485 bool ok;
486 int line = args.value(i: 0).toInt(ok: &ok);
487 if (ok) {
488 line = qMax(a: 1, b: line - 5);
489 } else {
490 line = listLineNumber();
491 if (line == -1)
492 line = qMax(a: progInfo->lineNumber(), b: ctxInfo.lineNumber() - 5);
493 }
494 for (int i = line; i < line + 10; ++i) {
495 message(text: QString::fromLatin1(str: "%0\t%1").arg(a: i).arg(a: progInfo->lineText(lineNumber: i)));
496 }
497 setListLineNumber(line + 10);
498 }
499 } else if (command == QLatin1String("info")) {
500 if (args.size() < 1) {
501 } else {
502 QString what = args.value(i: 0);
503 if (what == QLatin1String("locals")) {
504 QScriptValueIterator it(currentFrameContext()->activationObject());
505 while (it.hasNext()) {
506 it.next();
507 QString line;
508 line.append(s: it.name());
509 line.append(s: QLatin1String(" = "));
510 line.append(s: safeValueToString(value: it.value()));
511 message(text: line);
512 }
513 }
514 }
515 } else if (command == QLatin1String("help")) {
516 message(text: "continue - continue execution\n"
517 "step - step into statement\n"
518 "next - step over statement\n"
519 "list - show where you are\n"
520 "\n"
521 "break - set breakpoint\n"
522 "delete - remove breakpoint\n"
523 "disable - disable breakpoint\n"
524 "enable - enable breakpoint\n"
525 "\n"
526 "backtrace - show backtrace\n"
527 "up - one frame up\n"
528 "down - one frame down\n"
529 "frame - set frame\n"
530 "\n"
531 "info locals - show local variables");
532 } else {
533 errorMessage(text: QString::fromLatin1(str: "Undefined command \"%0\". Try \"help\".")
534 .arg(a: command));
535 }
536
537 return false;
538}
539
540
541// QScriptEngineAgent interface
542
543void ScriptDebuggerPrivate::scriptLoad(qint64 id, const QString &program,
544 const QString &fileName, int lineNumber)
545{
546 ScriptInfo *info = new ScriptInfo(program, fileName, lineNumber);
547 m_scripts.insert(akey: id, avalue: info);
548}
549
550void ScriptDebuggerPrivate::scriptUnload(qint64 id)
551{
552 ScriptInfo *info = m_scripts.take(akey: id);
553 delete info;
554}
555
556void ScriptDebuggerPrivate::functionEntry(qint64 scriptId)
557{
558 if (scriptId != -1) {
559 QScriptContext *ctx = engine()->currentContext();
560 QStack<qint64> ids = m_contextProgramIds.value(akey: ctx);
561 ids.push(t: scriptId);
562 m_contextProgramIds.insert(akey: ctx, avalue: ids);
563 }
564
565 if (mode() == StepOver)
566 ++m_stepDepth;
567}
568
569void ScriptDebuggerPrivate::functionExit(qint64 scriptId,
570 const QScriptValue &/*returnValue*/)
571{
572 if (scriptId != -1) {
573 QScriptContext *ctx = engine()->currentContext();
574 QStack<qint64> ids = m_contextProgramIds.value(akey: ctx);
575 Q_ASSERT(!ids.isEmpty());
576 Q_ASSERT(ids.top() == scriptId);
577 ids.pop();
578 m_contextProgramIds.insert(akey: ctx, avalue: ids);
579 }
580
581 if (mode() == StepOver)
582 --m_stepDepth;
583}
584
585void ScriptDebuggerPrivate::positionChange(qint64 scriptId,
586 int lineNumber, int /*columnNumber*/)
587{
588 ScriptInfo *info = 0;
589 bool enterInteractiveMode = false;
590
591 if (m_bpManager->hasBreakpoints()) {
592 // check if we hit a breakpoint
593 info = m_scripts.value(akey: scriptId);
594 QScriptContext *ctx = engine()->currentContext();
595 QScriptContextInfo ctxInfo(ctx);
596 QScriptValue callee = ctx->callee();
597
598 // try fileName:lineNumber
599 int bpid = m_bpManager->findBreakpoint(fileName: info->fileName(), lineNumber);
600 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(id: bpid)) {
601 message(text: QString::fromLatin1(str: "Breakpoint %0 at %1:%2")
602 .arg(a: bpid + 1).arg(a: info->fileName()).arg(a: lineNumber));
603 if (m_bpManager->isBreakpointSingleShot(id: bpid))
604 m_bpManager->removeBreakpoint(id: bpid);
605 }
606 if (bpid == -1) {
607 // try function
608 bpid = m_bpManager->findBreakpoint(function: callee);
609 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(id: bpid)) {
610 message(text: QString::fromLatin1(str: "Breakpoint %0, %1()")
611 .arg(a: bpid + 1).arg(a: ctxInfo.functionName()));
612 if (m_bpManager->isBreakpointSingleShot(id: bpid))
613 m_bpManager->removeBreakpoint(id: bpid);
614 }
615 }
616 if ((bpid == -1) && !ctxInfo.functionName().isEmpty()) {
617 // try functionName:fileName
618 bpid = m_bpManager->findBreakpoint(functionName: ctxInfo.functionName(), fileName: ctxInfo.fileName());
619 if ((bpid != -1) && m_bpManager->isBreakpointEnabled(id: bpid)) {
620 message(text: QString::fromLatin1(str: "Breakpoint %0, %1():%2").arg(a: bpid + 1)
621 .arg(a: ctxInfo.functionName()).arg(a: ctxInfo.fileName()));
622 if (m_bpManager->isBreakpointSingleShot(id: bpid))
623 m_bpManager->removeBreakpoint(id: bpid);
624 }
625 }
626
627 enterInteractiveMode = (bpid != -1);
628 }
629
630 switch (mode()) {
631 case Run:
632 break;
633
634 case StepInto:
635 enterInteractiveMode = true;
636 break;
637
638 case StepOver:
639 enterInteractiveMode = enterInteractiveMode || (m_stepDepth <= 0);
640 break;
641 }
642
643 if (enterInteractiveMode) {
644 if (!info)
645 info = m_scripts.value(akey: scriptId);
646 Q_ASSERT(info);
647 message(text: QString::fromLatin1(str: "%0\t%1").arg(a: lineNumber).arg(a: info->lineText(lineNumber)));
648 interactive();
649 }
650}
651
652void ScriptDebuggerPrivate::exceptionThrow(qint64 /*scriptId*/,
653 const QScriptValue &exception,
654 bool hasHandler)
655{
656 if (!hasHandler) {
657 errorMessage(text: QString::fromLatin1(str: "uncaught exception: %0").arg(a: exception.toString()));
658 QScriptContext *ctx = engine()->currentContext();
659 int lineNumber = QScriptContextInfo(ctx).lineNumber();
660 ScriptInfo *info = scriptInfo(context: ctx);
661 QString lineText = info ? info->lineText(lineNumber) : QString("(no source text available)");
662 message(text: QString::fromLatin1(str: "%0\t%1").arg(a: lineNumber).arg(a: lineText));
663 interactive();
664 }
665}
666
667
668
669ScriptDebugger::ScriptDebugger(QScriptEngine *engine)
670 : d_ptr(new ScriptDebuggerPrivate(engine))
671{
672 d_ptr->q_ptr = this;
673 engine->setAgent(d_ptr);
674}
675
676ScriptDebugger::ScriptDebugger(QScriptEngine *engine, ScriptDebuggerPrivate &dd)
677 : d_ptr(&dd)
678{
679 d_ptr->q_ptr = this;
680 engine->setAgent(d_ptr);
681}
682
683ScriptDebugger::~ScriptDebugger()
684{
685 delete d_ptr;
686 d_ptr = 0;
687}
688
689void ScriptDebugger::breakAtNextStatement()
690{
691 Q_D(ScriptDebugger);
692 d->setMode(ScriptDebuggerPrivate::StepInto);
693}
694
695void ScriptDebugger::setBreakpoint(const QString &fileName, int lineNumber)
696{
697 Q_D(ScriptDebugger);
698 d->m_bpManager->setBreakpoint(fileName, lineNumber);
699}
700
701void ScriptDebugger::setBreakpoint(const QString &functionName, const QString &fileName)
702{
703 Q_D(ScriptDebugger);
704 d->m_bpManager->setBreakpoint(functionName, fileName);
705}
706
707void ScriptDebugger::setBreakpoint(const QScriptValue &function)
708{
709 Q_D(ScriptDebugger);
710 d->m_bpManager->setBreakpoint(function);
711}
712
713QTextStream *ScriptDebugger::inputStream() const
714{
715 Q_D(const ScriptDebugger);
716 return d->m_inputStream;
717}
718
719void ScriptDebugger::setInputStream(QTextStream *inputStream)
720{
721 Q_D(ScriptDebugger);
722 d->m_inputStream = inputStream;
723}
724
725QTextStream *ScriptDebugger::outputStream() const
726{
727 Q_D(const ScriptDebugger);
728 return d->m_outputStream;
729}
730
731void ScriptDebugger::setOutputStream(QTextStream *outputStream)
732{
733 Q_D(ScriptDebugger);
734 d->m_outputStream = outputStream;
735}
736
737QTextStream *ScriptDebugger::errorStream() const
738{
739 Q_D(const ScriptDebugger);
740 return d->m_errorStream;
741}
742
743void ScriptDebugger::setErrorStream(QTextStream *errorStream)
744{
745 Q_D(ScriptDebugger);
746 d->m_errorStream = errorStream;
747}
748

source code of qtscript/examples/script/qsdbg/scriptdebugger.cpp