summaryrefslogtreecommitdiffstats
path: root/src/scripttools/debugging/qscriptdebuggercommand.cpp
blob: fa223ecf57f060223df920a8d3ebcd73c1686d49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtSCriptTools module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qscriptdebuggercommand_p.h"
#include "qscriptbreakpointdata_p.h"
#include "qscriptdebuggervalue_p.h"

#include <QtCore/qhash.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qstringlist.h>

Q_DECLARE_METATYPE(QScriptBreakpointData)
Q_DECLARE_METATYPE(QScriptDebuggerValue)

QT_BEGIN_NAMESPACE

/*!
  \since 4.5
  \class QScriptDebuggerCommand
  \internal

  \brief The QScriptDebuggerCommand class represents a command issued to a QScriptDebuggerFrontend.

  A debugger command is described by a command type and zero or more
  attributes.  Such commands are generated internally by the
  QScriptDebuggerFrontend class (through the scheduleXXX commands). A
  command is typically passed on to a QScriptDebuggerCommandExecutor
  that applies the command to a QScriptDebuggerBackend.
*/

class QScriptDebuggerCommandPrivate
{
public:
    QScriptDebuggerCommandPrivate();
    ~QScriptDebuggerCommandPrivate();

    QScriptDebuggerCommand::Type type;
    QHash<QScriptDebuggerCommand::Attribute, QVariant> attributes;
};

QScriptDebuggerCommandPrivate::QScriptDebuggerCommandPrivate()
    : type(QScriptDebuggerCommand::None)
{
}

QScriptDebuggerCommandPrivate::~QScriptDebuggerCommandPrivate()
{
}

/*!
  Constructs a QScriptDebuggerCommand of type None.
*/
QScriptDebuggerCommand::QScriptDebuggerCommand()
    : d_ptr(new QScriptDebuggerCommandPrivate)
{
    d_ptr->type = None;
}

/*!
  Constructs a QScriptDebuggerCommand of the given \a type, with no
  attributes defined.
*/
QScriptDebuggerCommand::QScriptDebuggerCommand(Type type)
    : d_ptr(new QScriptDebuggerCommandPrivate)
{
    d_ptr->type = type;
}

/*!
  Constructs a QScriptDebuggerCommand that is a copy of the \a other
  command.
*/
QScriptDebuggerCommand::QScriptDebuggerCommand(const QScriptDebuggerCommand &other)
    : d_ptr(new QScriptDebuggerCommandPrivate)
{
    *d_ptr = *other.d_ptr;
}

/*!
  Destroys this QScriptDebuggerCommand.
*/
QScriptDebuggerCommand::~QScriptDebuggerCommand()
{
}

/*!
  Assigns the \a other value to this QScriptDebuggerCommand.
*/
QScriptDebuggerCommand &QScriptDebuggerCommand::operator=(const QScriptDebuggerCommand &other)
{
    *d_ptr = *other.d_ptr;
    return *this;
}

/*!
  Returns the type of this command.
*/
QScriptDebuggerCommand::Type QScriptDebuggerCommand::type() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->type;
}

/*!
  Returns the value of the given \a attribute, or \a defaultValue
  if the attribute is not defined.
*/
QVariant QScriptDebuggerCommand::attribute(Attribute attribute,
                                           const QVariant &defaultValue) const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(attribute, defaultValue);
}

/*!
  Sets the \a value of the given \a attribute.
*/
void QScriptDebuggerCommand::setAttribute(Attribute attribute,
                                          const QVariant &value)
{
    Q_D(QScriptDebuggerCommand);
    if (!value.isValid())
        d->attributes.remove(attribute);
    else
        d->attributes[attribute] = value;
}

QHash<QScriptDebuggerCommand::Attribute, QVariant> QScriptDebuggerCommand::attributes() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes;
}

/*!
  Returns the FileName attribute of this command converted to a string.
  This function is provided for convenience.

  \sa attribute()
*/
QString QScriptDebuggerCommand::fileName() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(FileName).toString();
}

void QScriptDebuggerCommand::setFileName(const QString &fileName)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[FileName] = fileName;
}

/*!
  Returns the LineNumber attribute of this command converted to an int.
  This function is provided for convenience.

  \sa attribute()
*/
int QScriptDebuggerCommand::lineNumber() const
{ 
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(LineNumber, -1).toInt();
}

void QScriptDebuggerCommand::setLineNumber(int lineNumber)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[LineNumber] = lineNumber;
}

/*!
  Returns the ScriptID attribute of this command converted to a qint64.
  This function is provided for convenience.

  \sa attribute()
*/
qint64 QScriptDebuggerCommand::scriptId() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(ScriptID, -1).toLongLong();
}

void QScriptDebuggerCommand::setScriptId(qint64 id)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[ScriptID] = id;
}

QString QScriptDebuggerCommand::program() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(Program).toString();
}

void QScriptDebuggerCommand::setProgram(const QString &program)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[Program] = program;
}

int QScriptDebuggerCommand::breakpointId() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(BreakpointID, -1).toInt();
}

void QScriptDebuggerCommand::setBreakpointId(int id)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[BreakpointID] = id;
}

QScriptBreakpointData QScriptDebuggerCommand::breakpointData() const
{
    Q_D(const QScriptDebuggerCommand);
    return qvariant_cast<QScriptBreakpointData>(d->attributes.value(BreakpointData));
}

void QScriptDebuggerCommand::setBreakpointData(const QScriptBreakpointData &data)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[BreakpointData] = qVariantFromValue(data);
}

QScriptDebuggerValue QScriptDebuggerCommand::scriptValue() const
{
    Q_D(const QScriptDebuggerCommand);
    return qvariant_cast<QScriptDebuggerValue>(d->attributes.value(ScriptValue));
}

void QScriptDebuggerCommand::setScriptValue(const QScriptDebuggerValue &value)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[ScriptValue] = qVariantFromValue(value);
}

int QScriptDebuggerCommand::contextIndex() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(ContextIndex, -1).toInt();
}

void QScriptDebuggerCommand::setContextIndex(int index)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[ContextIndex] = index;
}

int QScriptDebuggerCommand::iteratorId() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(IteratorID, -1).toInt();
}

void QScriptDebuggerCommand::setIteratorId(int id)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[IteratorID] = id;
}

QString QScriptDebuggerCommand::name() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(Name).toString();
}

void QScriptDebuggerCommand::setName(const QString &name)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[Name] = name;
}

QScriptDebuggerValue QScriptDebuggerCommand::subordinateScriptValue() const
{
    Q_D(const QScriptDebuggerCommand);
    return qvariant_cast<QScriptDebuggerValue>(d->attributes.value(SubordinateScriptValue));
}

void QScriptDebuggerCommand::setSubordinateScriptValue(const QScriptDebuggerValue &value)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[SubordinateScriptValue] = qVariantFromValue(value);
}

int QScriptDebuggerCommand::snapshotId() const
{
    Q_D(const QScriptDebuggerCommand);
    return d->attributes.value(SnapshotID, -1).toInt();
}

void QScriptDebuggerCommand::setSnapshotId(int id)
{
    Q_D(QScriptDebuggerCommand);
    d->attributes[SnapshotID] = id;
}

/*!
  Returns true if this QScriptDebuggerCommand is equal to the \a other
  command, otherwise returns false.
*/
bool QScriptDebuggerCommand::operator==(const QScriptDebuggerCommand &other) const
{
    Q_D(const QScriptDebuggerCommand);
    const QScriptDebuggerCommandPrivate *od = other.d_func();
    if (d == od)
        return true;
    if (!d || !od)
        return false;
    return ((d->type == od->type)
            && (d->attributes == od->attributes));
}

/*!
  Returns true if this QScriptDebuggerCommand is not equal to the \a
  other command, otherwise returns false.
*/
bool QScriptDebuggerCommand::operator!=(const QScriptDebuggerCommand &other) const
{
    return !(*this == other);
}

QScriptDebuggerCommand QScriptDebuggerCommand::interruptCommand()
{
    QScriptDebuggerCommand cmd(Interrupt);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::continueCommand()
{
    QScriptDebuggerCommand cmd(Continue);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::stepIntoCommand(int count)
{
    QScriptDebuggerCommand cmd(StepInto);
    cmd.setAttribute(StepCount, count);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::stepOverCommand(int count)
{
    QScriptDebuggerCommand cmd(StepOver);
    cmd.setAttribute(StepCount, count);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::stepOutCommand()
{
    QScriptDebuggerCommand cmd(StepOut);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::runToLocationCommand(const QString &fileName, int lineNumber)
{
    QScriptDebuggerCommand cmd(RunToLocation);
    cmd.setFileName(fileName);
    cmd.setLineNumber(lineNumber);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::runToLocationCommand(qint64 scriptId, int lineNumber)
{
    QScriptDebuggerCommand cmd(RunToLocationByID);
    cmd.setScriptId(scriptId);
    cmd.setLineNumber(lineNumber);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::forceReturnCommand(int contextIndex, const QScriptDebuggerValue &value)
{
    QScriptDebuggerCommand cmd(ForceReturn);
    cmd.setContextIndex(contextIndex);
    cmd.setScriptValue(value);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::resumeCommand()
{
    QScriptDebuggerCommand cmd(Resume);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::setBreakpointCommand(const QString &fileName, int lineNumber)
{
    QScriptDebuggerCommand cmd(SetBreakpoint);
    cmd.setBreakpointData(QScriptBreakpointData(fileName, lineNumber));
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::setBreakpointCommand(const QScriptBreakpointData &data)
{
    QScriptDebuggerCommand cmd(SetBreakpoint);
    cmd.setBreakpointData(data);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::deleteBreakpointCommand(int id)
{
    QScriptDebuggerCommand cmd(DeleteBreakpoint);
    cmd.setBreakpointId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::deleteAllBreakpointsCommand()
{
    QScriptDebuggerCommand cmd(DeleteAllBreakpoints);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getBreakpointsCommand()
{
    QScriptDebuggerCommand cmd(GetBreakpoints);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getBreakpointDataCommand(int id)
{
    QScriptDebuggerCommand cmd(GetBreakpointData);
    cmd.setBreakpointId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::setBreakpointDataCommand(int id, const QScriptBreakpointData &data)
{
    QScriptDebuggerCommand cmd(SetBreakpointData);
    cmd.setBreakpointId(id);
    cmd.setBreakpointData(data);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getScriptsCommand()
{
    QScriptDebuggerCommand cmd(GetScripts);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getScriptDataCommand(qint64 id)
{
    QScriptDebuggerCommand cmd(GetScriptData);
    cmd.setScriptId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::scriptsCheckpointCommand()
{
    QScriptDebuggerCommand cmd(ScriptsCheckpoint);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getScriptsDeltaCommand()
{
    QScriptDebuggerCommand cmd(GetScriptsDelta);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::resolveScriptCommand(const QString &fileName)
{
    QScriptDebuggerCommand cmd(ResolveScript);
    cmd.setFileName(fileName);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getBacktraceCommand()
{
    QScriptDebuggerCommand cmd(GetBacktrace);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getContextCountCommand()
{
    QScriptDebuggerCommand cmd(GetContextCount);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getContextStateCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetContextState);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getContextInfoCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetContextInfo);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getContextIdCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetContextID);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getThisObjectCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetThisObject);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getActivationObjectCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetActivationObject);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getScopeChainCommand(int contextIndex)
{
    QScriptDebuggerCommand cmd(GetScopeChain);
    cmd.setContextIndex(contextIndex);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::contextsCheckpoint()
{
    QScriptDebuggerCommand cmd(ContextsCheckpoint);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getPropertyExpressionValue(
    int contextIndex, int lineNumber, const QStringList &path)
{
    QScriptDebuggerCommand cmd(GetPropertyExpressionValue);
    cmd.setContextIndex(contextIndex);
    cmd.setLineNumber(lineNumber);
    cmd.setAttribute(UserAttribute, path);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getCompletions(
    int contextIndex, const QStringList &path)
{
    QScriptDebuggerCommand cmd(GetCompletions);
    cmd.setContextIndex(contextIndex);
    cmd.setAttribute(UserAttribute, path);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::newScriptObjectSnapshotCommand()
{
    QScriptDebuggerCommand cmd(NewScriptObjectSnapshot);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::scriptObjectSnapshotCaptureCommand(int id, const QScriptDebuggerValue &object)
{
    Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
    QScriptDebuggerCommand cmd(ScriptObjectSnapshotCapture);
    cmd.setSnapshotId(id);
    cmd.setScriptValue(object);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::deleteScriptObjectSnapshotCommand(int id)
{
    QScriptDebuggerCommand cmd(DeleteScriptObjectSnapshot);
    cmd.setSnapshotId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::newScriptValueIteratorCommand(const QScriptDebuggerValue &object)
{
    QScriptDebuggerCommand cmd(NewScriptValueIterator);
    Q_ASSERT(object.type() == QScriptDebuggerValue::ObjectValue);
    cmd.setScriptValue(object);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::getPropertiesByIteratorCommand(int id, int count)
{
    Q_UNUSED(count);
    QScriptDebuggerCommand cmd(GetPropertiesByIterator);
    cmd.setIteratorId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::deleteScriptValueIteratorCommand(int id)
{
    QScriptDebuggerCommand cmd(DeleteScriptValueIterator);
    cmd.setIteratorId(id);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::evaluateCommand(
    int contextIndex, const QString &program, const QString &fileName, int lineNumber)
{
    QScriptDebuggerCommand cmd(Evaluate);
    cmd.setContextIndex(contextIndex);
    cmd.setProgram(program);
    cmd.setFileName(fileName);
    cmd.setLineNumber(lineNumber);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::scriptValueToStringCommand(const QScriptDebuggerValue &value)
{
    QScriptDebuggerCommand cmd(ScriptValueToString);
    cmd.setScriptValue(value);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::setScriptValuePropertyCommand(
    const QScriptDebuggerValue &object, const QString &name,
    const QScriptDebuggerValue &value)
{
    QScriptDebuggerCommand cmd(SetScriptValueProperty);
    cmd.setScriptValue(object);
    cmd.setName(name);
    cmd.setSubordinateScriptValue(value);
    return cmd;
}

QScriptDebuggerCommand QScriptDebuggerCommand::clearExceptionsCommand()
{
    QScriptDebuggerCommand cmd(ClearExceptions);
    return cmd;
}

/*!
  \fn QDataStream &operator<<(QDataStream &stream, const QScriptDebuggerCommand &command)
  \relates QScriptDebuggerCommand

  Writes the given \a command to the specified \a stream.
*/
QDataStream &operator<<(QDataStream &out, const QScriptDebuggerCommand &command)
{
    const QScriptDebuggerCommandPrivate *d = command.d_ptr.data();
    out << (quint32)d->type;
    out << (qint32)d->attributes.size();
    QHash<QScriptDebuggerCommand::Attribute, QVariant>::const_iterator it;
    for (it = d->attributes.constBegin(); it != d->attributes.constEnd(); ++it) {
        out << (quint32)it.key();
        out << it.value();
    }
    return out;
}

/*!
  \fn QDataStream &operator>>(QDataStream &stream, QScriptDebuggerCommand &command)
  \relates QScriptDebuggerCommand

  Reads a QScriptDebuggerCommand from the specified \a stream into the
  given \a command.
*/
QDataStream &operator>>(QDataStream &in, QScriptDebuggerCommand &command)
{
    QScriptDebuggerCommandPrivate *d = command.d_ptr.data();

    quint32 type;
    in >> type;
    d->type = QScriptDebuggerCommand::Type(type);

    qint32 attribCount;
    in >> attribCount;
    QHash<QScriptDebuggerCommand::Attribute, QVariant> attribs;
    for (qint32 i = 0; i < attribCount; ++i) {
        quint32 key;
        in >> key;
        QVariant value;
        in >> value;
        attribs[QScriptDebuggerCommand::Attribute(key)] = value;
    }
    d->attributes = attribs;

    return in;
}

QT_END_NAMESPACE
>PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { PyErr_Print(); return -1; } int err = _PyRun_InteractiveLoopObject(fp, filename_obj, flags); Py_DECREF(filename_obj); return err; } // Call _PyParser_ASTFromFile() with sys.stdin.encoding, sys.ps1 and sys.ps2 static int pyrun_one_parse_ast(FILE *fp, PyObject *filename, PyCompilerFlags *flags, PyArena *arena, mod_ty *pmod) { PyThreadState *tstate = _PyThreadState_GET(); // Get sys.stdin.encoding (as UTF-8) PyObject *attr; // borrowed ref PyObject *encoding_obj = NULL; const char *encoding = NULL; if (fp == stdin) { attr = _PySys_GetAttr(tstate, &_Py_ID(stdin)); if (attr && attr != Py_None) { encoding_obj = PyObject_GetAttr(attr, &_Py_ID(encoding)); if (encoding_obj) { encoding = PyUnicode_AsUTF8(encoding_obj); if (!encoding) { PyErr_Clear(); } } } } // Get sys.ps1 (as UTF-8) attr = _PySys_GetAttr(tstate, &_Py_ID(ps1)); PyObject *ps1_obj = NULL; const char *ps1 = ""; if (attr != NULL) { ps1_obj = PyObject_Str(attr); if (ps1_obj == NULL) { PyErr_Clear(); } else if (PyUnicode_Check(ps1_obj)) { ps1 = PyUnicode_AsUTF8(ps1_obj); if (ps1 == NULL) { PyErr_Clear(); ps1 = ""; } } } // Get sys.ps2 (as UTF-8) attr = _PySys_GetAttr(tstate, &_Py_ID(ps2)); PyObject *ps2_obj = NULL; const char *ps2 = ""; if (attr != NULL) { ps2_obj = PyObject_Str(attr); if (ps2_obj == NULL) { PyErr_Clear(); } else if (PyUnicode_Check(ps2_obj)) { ps2 = PyUnicode_AsUTF8(ps2_obj); if (ps2 == NULL) { PyErr_Clear(); ps2 = ""; } } } int errcode = 0; *pmod = _PyParser_ASTFromFile(fp, filename, encoding, Py_single_input, ps1, ps2, flags, &errcode, arena); Py_XDECREF(ps1_obj); Py_XDECREF(ps2_obj); Py_XDECREF(encoding_obj); if (*pmod == NULL) { if (errcode == E_EOF) { PyErr_Clear(); return E_EOF; } return -1; } return 0; } /* A PyRun_InteractiveOneObject() auxiliary function that does not print the * error on failure. */ static int PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { PyArena *arena = _PyArena_New(); if (arena == NULL) { return -1; } mod_ty mod; int parse_res = pyrun_one_parse_ast(fp, filename, flags, arena, &mod); if (parse_res != 0) { _PyArena_Free(arena); return parse_res; } PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { _PyArena_Free(arena); return -1; } PyObject *main_dict = PyModule_GetDict(main_module); // borrowed ref PyObject *res = run_mod(mod, filename, main_dict, main_dict, flags, arena); _PyArena_Free(arena); Py_DECREF(main_module); if (res == NULL) { return -1; } Py_DECREF(res); flush_io(); return 0; } int PyRun_InteractiveOneObject(FILE *fp, PyObject *filename, PyCompilerFlags *flags) { int res; res = PyRun_InteractiveOneObjectEx(fp, filename, flags); if (res == -1) { PyErr_Print(); flush_io(); } return res; } int PyRun_InteractiveOneFlags(FILE *fp, const char *filename_str, PyCompilerFlags *flags) { PyObject *filename; int res; filename = PyUnicode_DecodeFSDefault(filename_str); if (filename == NULL) { PyErr_Print(); return -1; } res = PyRun_InteractiveOneObject(fp, filename, flags); Py_DECREF(filename); return res; } /* Check whether a file maybe a pyc file: Look at the extension, the file type, and, if we may close it, at the first few bytes. */ static int maybe_pyc_file(FILE *fp, PyObject *filename, int closeit) { PyObject *ext = PyUnicode_FromString(".pyc"); if (ext == NULL) { return -1; } Py_ssize_t endswith = PyUnicode_Tailmatch(filename, ext, 0, PY_SSIZE_T_MAX, +1); Py_DECREF(ext); if (endswith) { return 1; } /* Only look into the file if we are allowed to close it, since it then should also be seekable. */ if (!closeit) { return 0; } /* Read only two bytes of the magic. If the file was opened in text mode, the bytes 3 and 4 of the magic (\r\n) might not be read as they are on disk. */ unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF; unsigned char buf[2]; /* Mess: In case of -x, the stream is NOT at its start now, and ungetc() was used to push back the first newline, which makes the current stream position formally undefined, and a x-platform nightmare. Unfortunately, we have no direct way to know whether -x was specified. So we use a terrible hack: if the current stream position is not 0, we assume -x was specified, and give up. Bug 132850 on SourceForge spells out the hopelessness of trying anything else (fseek and ftell don't work predictably x-platform for text-mode files). */ int ispyc = 0; if (ftell(fp) == 0) { if (fread(buf, 1, 2, fp) == 2 && ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic) ispyc = 1; rewind(fp); } return ispyc; } static int set_main_loader(PyObject *d, PyObject *filename, const char *loader_name) { PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *loader_type = _PyImport_GetImportlibExternalLoader(interp, loader_name); if (loader_type == NULL) { return -1; } PyObject *loader = PyObject_CallFunction(loader_type, "sO", "__main__", filename); Py_DECREF(loader_type); if (loader == NULL) { return -1; } if (PyDict_SetItemString(d, "__loader__", loader) < 0) { Py_DECREF(loader); return -1; } Py_DECREF(loader); return 0; } int _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, PyCompilerFlags *flags) { int ret = -1; PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) return -1; PyObject *dict = PyModule_GetDict(main_module); // borrowed ref int set_file_name = 0; int has_file = PyDict_ContainsString(dict, "__file__"); if (has_file < 0) { goto done; } if (!has_file) { if (PyDict_SetItemString(dict, "__file__", filename) < 0) { goto done; } if (PyDict_SetItemString(dict, "__cached__", Py_None) < 0) { goto done; } set_file_name = 1; } int pyc = maybe_pyc_file(fp, filename, closeit); if (pyc < 0) { goto done; } PyObject *v; if (pyc) { FILE *pyc_fp; /* Try to run a pyc file. First, re-open in binary */ if (closeit) { fclose(fp); } pyc_fp = _Py_fopen_obj(filename, "rb"); if (pyc_fp == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); goto done; } if (set_main_loader(dict, filename, "SourcelessFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; fclose(pyc_fp); goto done; } v = run_pyc_file(pyc_fp, dict, dict, flags); } else { /* When running from stdin, leave __main__.__loader__ alone */ if (PyUnicode_CompareWithASCIIString(filename, "<stdin>") != 0 && set_main_loader(dict, filename, "SourceFileLoader") < 0) { fprintf(stderr, "python: failed to set __main__.__loader__\n"); ret = -1; goto done; } v = pyrun_file(fp, filename, Py_file_input, dict, dict, closeit, flags); } flush_io(); if (v == NULL) { Py_CLEAR(main_module); PyErr_Print(); goto done; } Py_DECREF(v); ret = 0; done: if (set_file_name) { if (PyDict_DelItemString(dict, "__file__")) { PyErr_Clear(); } if (PyDict_DelItemString(dict, "__cached__")) { PyErr_Clear(); } } Py_XDECREF(main_module); return ret; } int PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags) { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { return -1; } int res = _PyRun_SimpleFileObject(fp, filename_obj, closeit, flags); Py_DECREF(filename_obj); return res; } int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) { PyObject *main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { return -1; } PyObject *dict = PyModule_GetDict(main_module); // borrowed ref PyObject *res = PyRun_StringFlags(command, Py_file_input, dict, dict, flags); Py_DECREF(main_module); if (res == NULL) { PyErr_Print(); return -1; } Py_DECREF(res); return 0; } static int parse_syntax_error(PyObject *err, PyObject **message, PyObject **filename, Py_ssize_t *lineno, Py_ssize_t *offset, Py_ssize_t* end_lineno, Py_ssize_t* end_offset, PyObject **text) { Py_ssize_t hold; PyObject *v; *message = NULL; *filename = NULL; /* new style errors. `err' is an instance */ *message = PyObject_GetAttr(err, &_Py_ID(msg)); if (!*message) goto finally; v = PyObject_GetAttr(err, &_Py_ID(filename)); if (!v) goto finally; if (v == Py_None) { Py_DECREF(v); _Py_DECLARE_STR(anon_string, "<string>"); *filename = Py_NewRef(&_Py_STR(anon_string)); } else { *filename = v; } v = PyObject_GetAttr(err, &_Py_ID(lineno)); if (!v) goto finally; hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *lineno = hold; v = PyObject_GetAttr(err, &_Py_ID(offset)); if (!v) goto finally; if (v == Py_None) { *offset = -1; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *offset = hold; } if (Py_TYPE(err) == (PyTypeObject*)PyExc_SyntaxError) { v = PyObject_GetAttr(err, &_Py_ID(end_lineno)); if (!v) { PyErr_Clear(); *end_lineno = *lineno; } else if (v == Py_None) { *end_lineno = *lineno; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *end_lineno = hold; } v = PyObject_GetAttr(err, &_Py_ID(end_offset)); if (!v) { PyErr_Clear(); *end_offset = -1; } else if (v == Py_None) { *end_offset = -1; Py_DECREF(v); } else { hold = PyLong_AsSsize_t(v); Py_DECREF(v); if (hold < 0 && PyErr_Occurred()) goto finally; *end_offset = hold; } } else { // SyntaxError subclasses *end_lineno = *lineno; *end_offset = -1; } v = PyObject_GetAttr(err, &_Py_ID(text)); if (!v) goto finally; if (v == Py_None) { Py_DECREF(v); *text = NULL; } else { *text = v; } return 1; finally: Py_XDECREF(*message); Py_XDECREF(*filename); return 0; } static int print_error_text(PyObject *f, Py_ssize_t offset, Py_ssize_t end_offset, PyObject *text_obj) { size_t caret_repetitions = (end_offset > 0 && end_offset > offset) ? end_offset - offset : 1; /* Convert text to a char pointer; return if error */ const char *text = PyUnicode_AsUTF8(text_obj); if (text == NULL) { return -1; } /* Convert offset from 1-based to 0-based */ offset--; /* Strip leading whitespace from text, adjusting offset as we go */ while (*text == ' ' || *text == '\t' || *text == '\f') { text++; offset--; } /* Calculate text length excluding trailing newline */ Py_ssize_t len = strlen(text); if (len > 0 && text[len-1] == '\n') { len--; } /* Clip offset to at most len */ if (offset > len) { offset = len; } /* Skip past newlines embedded in text */ for (;;) { const char *nl = strchr(text, '\n'); if (nl == NULL) { break; } Py_ssize_t inl = nl - text; if (inl >= offset) { break; } inl += 1; text += inl; len -= inl; offset -= (int)inl; } /* Print text */ if (PyFile_WriteString(" ", f) < 0) { return -1; } if (PyFile_WriteString(text, f) < 0) { return -1; } /* Make sure there's a newline at the end */ if (text[len] != '\n') { if (PyFile_WriteString("\n", f) < 0) { return -1; } } /* Don't print caret if it points to the left of the text */ if (offset < 0) { return 0; } /* Write caret line */ if (PyFile_WriteString(" ", f) < 0) { return -1; } while (--offset >= 0) { if (PyFile_WriteString(" ", f) < 0) { return -1; } } for (size_t caret_iter=0; caret_iter < caret_repetitions ; caret_iter++) { if (PyFile_WriteString("^", f) < 0) { return -1; } } if (PyFile_WriteString("\n", f) < 0) { return -1; } return 0; } int _Py_HandleSystemExit(int *exitcode_p) { int inspect = _Py_GetConfig()->inspect; if (inspect) { /* Don't exit if -i flag was given. This flag is set to 0 * when entering interactive mode for inspecting. */ return 0; } if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { return 0; } fflush(stdout); int exitcode = 0; PyObject *exc = PyErr_GetRaisedException(); if (exc == NULL) { goto done; } assert(PyExceptionInstance_Check(exc)); /* The error code should be in the `code' attribute. */ PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); if (code) { Py_SETREF(exc, code); if (exc == Py_None) { goto done; } } /* If we failed to dig out the 'code' attribute, * just let the else clause below print the error. */ if (PyLong_Check(exc)) { exitcode = (int)PyLong_AsLong(exc); } else { PyThreadState *tstate = _PyThreadState_GET(); PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); /* We clear the exception here to avoid triggering the assertion * in PyObject_Str that ensures it won't silently lose exception * details. */ PyErr_Clear(); if (sys_stderr != NULL && sys_stderr != Py_None) { PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW); } else { PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } PySys_WriteStderr("\n"); exitcode = 1; } done: Py_CLEAR(exc); *exitcode_p = exitcode; return 1; } static void handle_system_exit(void) { int exitcode; if (_Py_HandleSystemExit(&exitcode)) { Py_Exit(exitcode); } } static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { PyObject *typ = NULL, *tb = NULL; handle_system_exit(); PyObject *exc = _PyErr_GetRaisedException(tstate); if (exc == NULL) { goto done; } assert(PyExceptionInstance_Check(exc)); typ = Py_NewRef(Py_TYPE(exc)); tb = PyException_GetTraceback(exc); if (tb == NULL) { tb = Py_NewRef(Py_None); } if (set_sys_last_vars) { if (_PySys_SetAttr(&_Py_ID(last_exc), exc) < 0) { _PyErr_Clear(tstate); } /* Legacy version: */ if (_PySys_SetAttr(&_Py_ID(last_type), typ) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_value), exc) < 0) { _PyErr_Clear(tstate); } if (_PySys_SetAttr(&_Py_ID(last_traceback), tb) < 0) { _PyErr_Clear(tstate); } } PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { PyErr_Clear(); goto done; } _PyErr_WriteUnraisableMsg("in audit hook", NULL); } if (hook) { PyObject* args[3] = {typ, exc, tb}; PyObject *result = PyObject_Vectorcall(hook, args, 3, NULL); if (result == NULL) { handle_system_exit(); PyObject *exc2 = _PyErr_GetRaisedException(tstate); assert(exc2 && PyExceptionInstance_Check(exc2)); fflush(stdout); PySys_WriteStderr("Error in sys.excepthook:\n"); PyErr_DisplayException(exc2); PySys_WriteStderr("\nOriginal exception was:\n"); PyErr_DisplayException(exc); Py_DECREF(exc2); } else { Py_DECREF(result); } } else { PySys_WriteStderr("sys.excepthook is missing\n"); PyErr_DisplayException(exc); } done: Py_XDECREF(typ); Py_XDECREF(exc); Py_XDECREF(tb); } void _PyErr_Print(PyThreadState *tstate) { _PyErr_PrintEx(tstate, 1); } void PyErr_PrintEx(int set_sys_last_vars) { PyThreadState *tstate = _PyThreadState_GET(); _PyErr_PrintEx(tstate, set_sys_last_vars); } void PyErr_Print(void) { PyErr_PrintEx(1); } struct exception_print_context { PyObject *file; PyObject *seen; // Prevent cycles in recursion int exception_group_depth; // nesting level of current exception group bool need_close; // Need a closing bottom frame int max_group_width; // Maximum number of children of each EG int max_group_depth; // Maximum nesting level of EGs }; #define EXC_MARGIN(ctx) ((ctx)->exception_group_depth ? "| " : "") #define EXC_INDENT(ctx) (2 * (ctx)->exception_group_depth) static int write_indented_margin(struct exception_print_context *ctx, PyObject *f) { return _Py_WriteIndentedMargin(EXC_INDENT(ctx), EXC_MARGIN(ctx), f); } static int print_exception_invalid_type(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } const char *const msg = "TypeError: print_exception(): Exception expected " "for value, "; if (PyFile_WriteString(msg, f) < 0) { return -1; } if (PyFile_WriteString(Py_TYPE(value)->tp_name, f) < 0) { return -1; } if (PyFile_WriteString(" found\n", f) < 0) { return -1; } return 0; } static int print_exception_traceback(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; int err = 0; PyObject *tb = PyException_GetTraceback(value); if (tb && tb != Py_None) { const char *header = EXCEPTION_TB_HEADER; const char *header_margin = EXC_MARGIN(ctx); if (_PyBaseExceptionGroup_Check(value)) { header = EXCEPTION_GROUP_TB_HEADER; if (ctx->exception_group_depth == 1) { header_margin = "+ "; } } err = _PyTraceBack_Print_Indented( tb, EXC_INDENT(ctx), EXC_MARGIN(ctx), header_margin, header, f); } Py_XDECREF(tb); return err; } static int print_exception_file_and_line(struct exception_print_context *ctx, PyObject **value_p) { PyObject *f = ctx->file; PyObject *tmp; int res = PyObject_GetOptionalAttr(*value_p, &_Py_ID(print_file_and_line), &tmp); if (res <= 0) { if (res < 0) { PyErr_Clear(); } return 0; } Py_DECREF(tmp); PyObject *message, *filename, *text; Py_ssize_t lineno, offset, end_lineno, end_offset; if (!parse_syntax_error(*value_p, &message, &filename, &lineno, &offset, &end_lineno, &end_offset, &text)) { PyErr_Clear(); return 0; } Py_SETREF(*value_p, message); PyObject *line = PyUnicode_FromFormat(" File \"%S\", line %zd\n", filename, lineno); Py_DECREF(filename); if (line == NULL) { goto error; } if (write_indented_margin(ctx, f) < 0) { goto error; } if (PyFile_WriteObject(line, f, Py_PRINT_RAW) < 0) { goto error; } Py_CLEAR(line); if (text != NULL) { Py_ssize_t line_size; const char *error_line = PyUnicode_AsUTF8AndSize(text, &line_size); // If the location of the error spawn multiple lines, we want // to just print the first one and highlight everything until // the end of that one since we don't support multi-line error // messages. if (end_lineno > lineno) { end_offset = (error_line != NULL) ? line_size : -1; } // Limit the amount of '^' that we can display to // the size of the text in the source line. if (error_line != NULL && end_offset > line_size + 1) { end_offset = line_size + 1; } if (print_error_text(f, offset, end_offset, text) < 0) { goto error; } Py_DECREF(text); } assert(!PyErr_Occurred()); return 0; error: Py_XDECREF(line); Py_XDECREF(text); return -1; } /* Prints the message line: module.qualname[: str(exc)] */ static int print_exception_message(struct exception_print_context *ctx, PyObject *type, PyObject *value) { PyObject *f = ctx->file; assert(PyExceptionClass_Check(type)); if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *modulename = PyObject_GetAttr(type, &_Py_ID(__module__)); if (modulename == NULL || !PyUnicode_Check(modulename)) { Py_XDECREF(modulename); PyErr_Clear(); if (PyFile_WriteString("<unknown>.", f) < 0) { return -1; } } else { if (!_PyUnicode_Equal(modulename, &_Py_ID(builtins)) && !_PyUnicode_Equal(modulename, &_Py_ID(__main__))) { int res = PyFile_WriteObject(modulename, f, Py_PRINT_RAW); Py_DECREF(modulename); if (res < 0) { return -1; } if (PyFile_WriteString(".", f) < 0) { return -1; } } else { Py_DECREF(modulename); } } PyObject *qualname = PyType_GetQualName((PyTypeObject *)type); if (qualname == NULL || !PyUnicode_Check(qualname)) { Py_XDECREF(qualname); PyErr_Clear(); if (PyFile_WriteString("<unknown>", f) < 0) { return -1; } } else { int res = PyFile_WriteObject(qualname, f, Py_PRINT_RAW); Py_DECREF(qualname); if (res < 0) { return -1; } } if (Py_IsNone(value)) { return 0; } PyObject *s = PyObject_Str(value); if (s == NULL) { PyErr_Clear(); if (PyFile_WriteString(": <exception str() failed>", f) < 0) { return -1; } } else { /* only print colon if the str() of the object is not the empty string */ if (!PyUnicode_Check(s) || PyUnicode_GetLength(s) != 0) { if (PyFile_WriteString(": ", f) < 0) { Py_DECREF(s); return -1; } } int res = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_DECREF(s); if (res < 0) { return -1; } } return 0; } static int print_exception_suggestions(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; PyObject *suggestions = _Py_Offer_Suggestions(value); if (suggestions) { if (PyFile_WriteObject(suggestions, f, Py_PRINT_RAW) < 0) { goto error; } Py_DECREF(suggestions); } else if (PyErr_Occurred()) { PyErr_Clear(); } return 0; error: Py_XDECREF(suggestions); return -1; } static int print_exception_notes(struct exception_print_context *ctx, PyObject *notes) { PyObject *f = ctx->file; if (notes == NULL) { return 0; } if (!PySequence_Check(notes) || PyUnicode_Check(notes) || PyBytes_Check(notes)) { int res = 0; if (write_indented_margin(ctx, f) < 0) { res = -1; } PyObject *s = PyObject_Repr(notes); if (s == NULL) { PyErr_Clear(); res = PyFile_WriteString("<__notes__ repr() failed>", f); } else { res = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_DECREF(s); } if (PyFile_WriteString("\n", f) < 0) { res = -1; } return res; } Py_ssize_t num_notes = PySequence_Length(notes); PyObject *lines = NULL; for (Py_ssize_t ni = 0; ni < num_notes; ni++) { PyObject *note = PySequence_GetItem(notes, ni); PyObject *note_str = PyObject_Str(note); Py_DECREF(note); if (note_str == NULL) { PyErr_Clear(); if (PyFile_WriteString("<note str() failed>", f) < 0) { goto error; } } else { lines = PyUnicode_Splitlines(note_str, 1); Py_DECREF(note_str); if (lines == NULL) { goto error; } Py_ssize_t n = PyList_GET_SIZE(lines); for (Py_ssize_t i = 0; i < n; i++) { PyObject *line = PyList_GET_ITEM(lines, i); assert(PyUnicode_Check(line)); if (write_indented_margin(ctx, f) < 0) { goto error; } if (PyFile_WriteObject(line, f, Py_PRINT_RAW) < 0) { goto error; } } Py_CLEAR(lines); } if (PyFile_WriteString("\n", f) < 0) { goto error; } } return 0; error: Py_XDECREF(lines); return -1; } static int print_exception(struct exception_print_context *ctx, PyObject *value) { PyObject *notes = NULL; PyObject *f = ctx->file; if (!PyExceptionInstance_Check(value)) { return print_exception_invalid_type(ctx, value); } Py_INCREF(value); fflush(stdout); if (print_exception_traceback(ctx, value) < 0) { goto error; } /* grab the type and notes now because value can change below */ PyObject *type = (PyObject *) Py_TYPE(value); if (PyObject_GetOptionalAttr(value, &_Py_ID(__notes__), &notes) < 0) { goto error; } if (print_exception_file_and_line(ctx, &value) < 0) { goto error; } if (print_exception_message(ctx, type, value) < 0) { goto error; } if (print_exception_suggestions(ctx, value) < 0) { goto error; } if (PyFile_WriteString("\n", f) < 0) { goto error; } if (print_exception_notes(ctx, notes) < 0) { goto error; } Py_XDECREF(notes); Py_DECREF(value); assert(!PyErr_Occurred()); return 0; error: Py_XDECREF(notes); Py_DECREF(value); return -1; } static const char cause_message[] = "The above exception was the direct cause " "of the following exception:\n"; static const char context_message[] = "During handling of the above exception, " "another exception occurred:\n"; static int print_exception_recursive(struct exception_print_context*, PyObject*); static int print_chained(struct exception_print_context* ctx, PyObject *value, const char * message, const char *tag) { PyObject *f = ctx->file; if (_Py_EnterRecursiveCall(" in print_chained")) { return -1; } bool need_close = ctx->need_close; int res = print_exception_recursive(ctx, value); ctx->need_close = need_close; _Py_LeaveRecursiveCall(); if (res < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString("\n", f) < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString(message, f) < 0) { return -1; } if (write_indented_margin(ctx, f) < 0) { return -1; } if (PyFile_WriteString("\n", f) < 0) { return -1; } return 0; } /* Return true if value is in seen or there was a lookup error. * Return false if lookup succeeded and the item was not found. * We suppress errors because this makes us err on the side of * under-printing which is better than over-printing irregular * exceptions (e.g., unhashable ones). */ static bool print_exception_seen_lookup(struct exception_print_context *ctx, PyObject *value) { PyObject *check_id = PyLong_FromVoidPtr(value); if (check_id == NULL) { PyErr_Clear(); return true; } int in_seen = PySet_Contains(ctx->seen, check_id); Py_DECREF(check_id); if (in_seen == -1) { PyErr_Clear(); return true; } if (in_seen == 1) { /* value is in seen */ return true; } return false; } static int print_exception_cause_and_context(struct exception_print_context *ctx, PyObject *value) { PyObject *value_id = PyLong_FromVoidPtr(value); if (value_id == NULL || PySet_Add(ctx->seen, value_id) == -1) { PyErr_Clear(); Py_XDECREF(value_id); return 0; } Py_DECREF(value_id); if (!PyExceptionInstance_Check(value)) { return 0; } PyObject *cause = PyException_GetCause(value); if (cause) { int err = 0; if (!print_exception_seen_lookup(ctx, cause)) { err = print_chained(ctx, cause, cause_message, "cause"); } Py_DECREF(cause); return err; } if (((PyBaseExceptionObject *)value)->suppress_context) { return 0; } PyObject *context = PyException_GetContext(value); if (context) { int err = 0; if (!print_exception_seen_lookup(ctx, context)) { err = print_chained(ctx, context, context_message, "context"); } Py_DECREF(context); return err; } return 0; } static int print_exception_group(struct exception_print_context *ctx, PyObject *value) { PyObject *f = ctx->file; if (ctx->exception_group_depth > ctx->max_group_depth) { /* depth exceeds limit */ if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *line = PyUnicode_FromFormat("... (max_group_depth is %d)\n", ctx->max_group_depth); if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); return err; } if (ctx->exception_group_depth == 0) { ctx->exception_group_depth += 1; } if (print_exception(ctx, value) < 0) { return -1; } PyObject *excs = ((PyBaseExceptionGroupObject *)value)->excs; assert(excs && PyTuple_Check(excs)); Py_ssize_t num_excs = PyTuple_GET_SIZE(excs); assert(num_excs > 0); Py_ssize_t n; if (num_excs <= ctx->max_group_width) { n = num_excs; } else { n = ctx->max_group_width + 1; } ctx->need_close = false; for (Py_ssize_t i = 0; i < n; i++) { bool last_exc = (i == n - 1); if (last_exc) { // The closing frame may be added in a recursive call ctx->need_close = true; } if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } bool truncated = (i >= ctx->max_group_width); PyObject *line; if (!truncated) { line = PyUnicode_FromFormat( "%s+---------------- %zd ----------------\n", (i == 0) ? "+-" : " ", i + 1); } else { line = PyUnicode_FromFormat( "%s+---------------- ... ----------------\n", (i == 0) ? "+-" : " "); } if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); if (err < 0) { return -1; } ctx->exception_group_depth += 1; PyObject *exc = PyTuple_GET_ITEM(excs, i); if (!truncated) { if (_Py_EnterRecursiveCall(" in print_exception_group")) { return -1; } int res = print_exception_recursive(ctx, exc); _Py_LeaveRecursiveCall(); if (res < 0) { return -1; } } else { Py_ssize_t excs_remaining = num_excs - ctx->max_group_width; if (write_indented_margin(ctx, f) < 0) { return -1; } PyObject *line = PyUnicode_FromFormat( "and %zd more exception%s\n", excs_remaining, excs_remaining > 1 ? "s" : ""); if (line == NULL) { return -1; } int err = PyFile_WriteObject(line, f, Py_PRINT_RAW); Py_DECREF(line); if (err < 0) { return -1; } } if (last_exc && ctx->need_close) { if (_Py_WriteIndent(EXC_INDENT(ctx), f) < 0) { return -1; } if (PyFile_WriteString( "+------------------------------------\n", f) < 0) { return -1; } ctx->need_close = false; } ctx->exception_group_depth -= 1; } if (ctx->exception_group_depth == 1) { ctx->exception_group_depth -= 1; } return 0; } static int print_exception_recursive(struct exception_print_context *ctx, PyObject *value) { if (_Py_EnterRecursiveCall(" in print_exception_recursive")) { return -1; } if (ctx->seen != NULL) { /* Exception chaining */ if (print_exception_cause_and_context(ctx, value) < 0) { goto error; } } if (!_PyBaseExceptionGroup_Check(value)) { if (print_exception(ctx, value) < 0) { goto error; } } else if (print_exception_group(ctx, value) < 0) { goto error; } assert(!PyErr_Occurred()); _Py_LeaveRecursiveCall(); return 0; error: _Py_LeaveRecursiveCall(); return -1; } #define PyErr_MAX_GROUP_WIDTH 15 #define PyErr_MAX_GROUP_DEPTH 10 void _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) { assert(file != NULL && file != Py_None); if (PyExceptionInstance_Check(value) && tb != NULL && PyTraceBack_Check(tb)) { /* Put the traceback on the exception, otherwise it won't get displayed. See issue #18776. */ PyObject *cur_tb = PyException_GetTraceback(value); if (cur_tb == NULL) { PyException_SetTraceback(value, tb); } else { Py_DECREF(cur_tb); } } struct exception_print_context ctx; ctx.file = file; ctx.exception_group_depth = 0; ctx.need_close = false; ctx.max_group_width = PyErr_MAX_GROUP_WIDTH; ctx.max_group_depth = PyErr_MAX_GROUP_DEPTH; /* We choose to ignore seen being possibly NULL, and report at least the main exception (it could be a MemoryError). */ ctx.seen = PySet_New(NULL); if (ctx.seen == NULL) { PyErr_Clear(); } if (print_exception_recursive(&ctx, value) < 0) { PyErr_Clear(); _PyObject_Dump(value); fprintf(stderr, "lost sys.stderr\n"); } Py_XDECREF(ctx.seen); /* Call file.flush() */ PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (!res) { /* Silently ignore file.flush() error */ PyErr_Clear(); } else { Py_DECREF(res); } } void PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); if (file == NULL) { _PyObject_Dump(value); fprintf(stderr, "lost sys.stderr\n"); return; } if (file == Py_None) { return; } Py_INCREF(file); _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } void _PyErr_DisplayException(PyObject *file, PyObject *exc) { _PyErr_Display(file, NULL, exc, NULL); } void PyErr_DisplayException(PyObject *exc) { PyErr_Display(NULL, exc, NULL); } PyObject * PyRun_StringFlags(const char *str, int start, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { PyObject *ret = NULL; mod_ty mod; PyArena *arena; arena = _PyArena_New(); if (arena == NULL) return NULL; _Py_DECLARE_STR(anon_string, "<string>"); mod = _PyParser_ASTFromString( str, &_Py_STR(anon_string), start, flags, arena); if (mod != NULL) ret = run_mod(mod, &_Py_STR(anon_string), globals, locals, flags, arena); _PyArena_Free(arena); return ret; } static PyObject * pyrun_file(FILE *fp, PyObject *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) { PyArena *arena = _PyArena_New(); if (arena == NULL) { return NULL; } mod_ty mod; mod = _PyParser_ASTFromFile(fp, filename, NULL, start, NULL, NULL, flags, NULL, arena); if (closeit) { fclose(fp); } PyObject *ret; if (mod != NULL) { ret = run_mod(mod, filename, globals, locals, flags, arena); } else { ret = NULL; } _PyArena_Free(arena); return ret; } PyObject * PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags) { PyObject *filename_obj = PyUnicode_DecodeFSDefault(filename); if (filename_obj == NULL) { return NULL; } PyObject *res = pyrun_file(fp, filename_obj, start, globals, locals, closeit, flags); Py_DECREF(filename_obj); return res; } static void flush_io_stream(PyThreadState *tstate, PyObject *name) { PyObject *f = _PySys_GetAttr(tstate, name); if (f != NULL) { PyObject *r = PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); if (r) { Py_DECREF(r); } else { PyErr_Clear(); } } } static void flush_io(void) { PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); flush_io_stream(tstate, &_Py_ID(stderr)); flush_io_stream(tstate, &_Py_ID(stdout)); _PyErr_SetRaisedException(tstate, exc); } static PyObject * run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, PyObject *locals) { PyObject *v; /* * We explicitly re-initialize _Py_UnhandledKeyboardInterrupt every eval * _just in case_ someone is calling into an embedded Python where they * don't care about an uncaught KeyboardInterrupt exception (why didn't they * leave config.install_signal_handlers set to 0?!?) but then later call * Py_Main() itself (which _checks_ this flag and dies with a signal after * its interpreter exits). We don't want a previous embedded interpreter's * uncaught exception to trigger an unexplained signal exit from a future * Py_Main() based one. */ // XXX Isn't this dealt with by the move to _PyRuntimeState? _PyRuntime.signals.unhandled_keyboard_interrupt = 0; /* Set globals['__builtins__'] if it doesn't exist */ if (globals != NULL) { int has_builtins = PyDict_ContainsString(globals, "__builtins__"); if (has_builtins < 0) { return NULL; } if (!has_builtins) { if (PyDict_SetItemString(globals, "__builtins__", tstate->interp->builtins) < 0) { return NULL; } } } v = PyEval_EvalCode((PyObject*)co, globals, locals); if (!v && _PyErr_Occurred(tstate) == PyExc_KeyboardInterrupt) { _PyRuntime.signals.unhandled_keyboard_interrupt = 1; } return v; } static PyObject * run_mod(mod_ty mod, PyObject *filename, PyObject *globals, PyObject *locals, PyCompilerFlags *flags, PyArena *arena) { PyThreadState *tstate = _PyThreadState_GET(); PyCodeObject *co = _PyAST_Compile(mod, filename, flags, -1, arena); if (co == NULL) return NULL; if (_PySys_Audit(tstate, "exec", "O", co) < 0) { Py_DECREF(co); return NULL; } PyObject *v = run_eval_code_obj(tstate, co, globals, locals); Py_DECREF(co); return v; } static PyObject * run_pyc_file(FILE *fp, PyObject *globals, PyObject *locals, PyCompilerFlags *flags) { PyThreadState *tstate = _PyThreadState_GET(); PyCodeObject *co; PyObject *v; long magic; long PyImport_GetMagicNumber(void); magic = PyMarshal_ReadLongFromFile(fp); if (magic != PyImport_GetMagicNumber()) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "Bad magic number in .pyc file"); goto error; } /* Skip the rest of the header. */ (void) PyMarshal_ReadLongFromFile(fp); (void) PyMarshal_ReadLongFromFile(fp); (void) PyMarshal_ReadLongFromFile(fp); if (PyErr_Occurred()) { goto error; } v = PyMarshal_ReadLastObjectFromFile(fp); if (v == NULL || !PyCode_Check(v)) { Py_XDECREF(v); PyErr_SetString(PyExc_RuntimeError, "Bad code object in .pyc file"); goto error; } fclose(fp); co = (PyCodeObject *)v; v = run_eval_code_obj(tstate, co, globals, locals); if (v && flags) flags->cf_flags |= (co->co_flags & PyCF_MASK); Py_DECREF(co); return v; error: fclose(fp); return NULL; } PyObject * Py_CompileStringObject(const char *str, PyObject *filename, int start, PyCompilerFlags *flags, int optimize) { PyCodeObject *co; mod_ty mod; PyArena *arena = _PyArena_New(); if (arena == NULL) return NULL; mod = _PyParser_ASTFromString(str, filename, start, flags, arena); if (mod == NULL) { _PyArena_Free(arena); return NULL; } if (flags && (flags->cf_flags & PyCF_ONLY_AST)) { if ((flags->cf_flags & PyCF_OPTIMIZED_AST) == PyCF_OPTIMIZED_AST) { if (_PyCompile_AstOptimize(mod, filename, flags, optimize, arena) < 0) { return NULL; } } PyObject *result = PyAST_mod2obj(mod); _PyArena_Free(arena); return result; } co = _PyAST_Compile(mod, filename, flags, optimize, arena); _PyArena_Free(arena); return (PyObject *)co; } PyObject * Py_CompileStringExFlags(const char *str, const char *filename_str, int start, PyCompilerFlags *flags, int optimize) { PyObject *filename, *co; filename = PyUnicode_DecodeFSDefault(filename_str); if (filename == NULL) return NULL; co = Py_CompileStringObject(str, filename, start, flags, optimize); Py_DECREF(filename); return co; } const char * _Py_SourceAsString(PyObject *cmd, const char *funcname, const char *what, PyCompilerFlags *cf, PyObject **cmd_copy) { const char *str; Py_ssize_t size; Py_buffer view; *cmd_copy = NULL; if (PyUnicode_Check(cmd)) { cf->cf_flags |= PyCF_IGNORE_COOKIE; str = PyUnicode_AsUTF8AndSize(cmd, &size); if (str == NULL) return NULL; } else if (PyBytes_Check(cmd)) { str = PyBytes_AS_STRING(cmd); size = PyBytes_GET_SIZE(cmd); } else if (PyByteArray_Check(cmd)) { str = PyByteArray_AS_STRING(cmd); size = PyByteArray_GET_SIZE(cmd); } else if (PyObject_GetBuffer(cmd, &view, PyBUF_SIMPLE) == 0) { /* Copy to NUL-terminated buffer. */ *cmd_copy = PyBytes_FromStringAndSize( (const char *)view.buf, view.len); PyBuffer_Release(&view); if (*cmd_copy == NULL) { return NULL; } str = PyBytes_AS_STRING(*cmd_copy); size = PyBytes_GET_SIZE(*cmd_copy); } else { PyErr_Format(PyExc_TypeError, "%s() arg 1 must be a %s object", funcname, what); return NULL; } if (strlen(str) != (size_t)size) { PyErr_SetString(PyExc_SyntaxError, "source code string cannot contain null bytes"); Py_CLEAR(*cmd_copy); return NULL; } return str; } #if defined(USE_STACKCHECK) #if defined(WIN32) && defined(_MSC_VER) /* Stack checking for Microsoft C */ #include <malloc.h> #include <excpt.h> /* * Return non-zero when we run out of memory on the stack; zero otherwise. */ int PyOS_CheckStack(void) { __try { /* alloca throws a stack overflow exception if there's not enough space left on the stack */ alloca(PYOS_STACK_MARGIN * sizeof(void*)); return 0; } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { int errcode = _resetstkoflw(); if (errcode == 0) { Py_FatalError("Could not reset the stack!"); } } return 1; } #endif /* WIN32 && _MSC_VER */ /* Alternate implementations can be added here... */ #endif /* USE_STACKCHECK */ /* Deprecated C API functions still provided for binary compatibility */ #undef PyRun_AnyFile PyAPI_FUNC(int) PyRun_AnyFile(FILE *fp, const char *name) { return PyRun_AnyFileExFlags(fp, name, 0, NULL); } #undef PyRun_AnyFileEx PyAPI_FUNC(int) PyRun_AnyFileEx(FILE *fp, const char *name, int closeit) { return PyRun_AnyFileExFlags(fp, name, closeit, NULL); } #undef PyRun_AnyFileFlags PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *fp, const char *name, PyCompilerFlags *flags) { return PyRun_AnyFileExFlags(fp, name, 0, flags); } #undef PyRun_File PyAPI_FUNC(PyObject *) PyRun_File(FILE *fp, const char *p, int s, PyObject *g, PyObject *l) { return PyRun_FileExFlags(fp, p, s, g, l, 0, NULL); } #undef PyRun_FileEx PyAPI_FUNC(PyObject *) PyRun_FileEx(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, int c) { return PyRun_FileExFlags(fp, p, s, g, l, c, NULL); } #undef PyRun_FileFlags PyAPI_FUNC(PyObject *) PyRun_FileFlags(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, PyCompilerFlags *flags) { return PyRun_FileExFlags(fp, p, s, g, l, 0, flags); } #undef PyRun_SimpleFile PyAPI_FUNC(int) PyRun_SimpleFile(FILE *f, const char *p) { return PyRun_SimpleFileExFlags(f, p, 0, NULL); } #undef PyRun_SimpleFileEx PyAPI_FUNC(int) PyRun_SimpleFileEx(FILE *f, const char *p, int c) { return PyRun_SimpleFileExFlags(f, p, c, NULL); } #undef PyRun_String PyAPI_FUNC(PyObject *) PyRun_String(const char *str, int s, PyObject *g, PyObject *l) { return PyRun_StringFlags(str, s, g, l, NULL); } #undef PyRun_SimpleString PyAPI_FUNC(int) PyRun_SimpleString(const char *s) { return PyRun_SimpleStringFlags(s, NULL); } #undef Py_CompileString PyAPI_FUNC(PyObject *) Py_CompileString(const char *str, const char *p, int s) { return Py_CompileStringExFlags(str, p, s, NULL, -1); } #undef Py_CompileStringFlags PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *str, const char *p, int s, PyCompilerFlags *flags) { return Py_CompileStringExFlags(str, p, s, flags, -1); } #undef PyRun_InteractiveOne PyAPI_FUNC(int) PyRun_InteractiveOne(FILE *f, const char *p) { return PyRun_InteractiveOneFlags(f, p, NULL); } #undef PyRun_InteractiveLoop PyAPI_FUNC(int) PyRun_InteractiveLoop(FILE *f, const char *p) { return PyRun_InteractiveLoopFlags(f, p, NULL); } #ifdef __cplusplus } #endif