summaryrefslogtreecommitdiffstats
path: root/Objects/stringlib/join.h
blob: 5568b31dab860f576233e40afde43aff57d013dd (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
/* stringlib: bytes joining implementation */

#if STRINGLIB_SIZEOF_CHAR != 1
#error join.h only compatible with byte-wise strings
#endif

Py_LOCAL_INLINE(PyObject *)
STRINGLIB(bytes_join)(PyObject *sep, PyObject *iterable)
{
    char *sepstr = STRINGLIB_STR(sep);
    const Py_ssize_t seplen = STRINGLIB_LEN(sep);
    PyObject *res = NULL;
    char *p;
    Py_ssize_t seqlen = 0;
    Py_ssize_t sz = 0;
    Py_ssize_t i, nbufs;
    PyObject *seq, *item;
    Py_buffer *buffers = NULL;
#define NB_STATIC_BUFFERS 10
    Py_buffer static_buffers[NB_STATIC_BUFFERS];

    seq = PySequence_Fast(iterable, "can only join an iterable");
    if (seq == NULL) {
        return NULL;
    }

    seqlen = PySequence_Fast_GET_SIZE(seq);
    if (seqlen == 0) {
        Py_DECREF(seq);
        return STRINGLIB_NEW(NULL, 0);
    }
#ifndef STRINGLIB_MUTABLE
    if (seqlen == 1) {
        item = PySequence_Fast_GET_ITEM(seq, 0);
        if (STRINGLIB_CHECK_EXACT(item)) {
            Py_INCREF(item);
            Py_DECREF(seq);
            return item;
        }
    }
#endif
    if (seqlen > NB_STATIC_BUFFERS) {
        buffers = PyMem_NEW(Py_buffer, seqlen);
        if (buffers == NULL) {
            Py_DECREF(seq);
            PyErr_NoMemory();
            return NULL;
        }
    }
    else {
        buffers = static_buffers;
    }

    /* Here is the general case.  Do a pre-pass to figure out the total
     * amount of space we'll need (sz), and see whether all arguments are
     * buffer-compatible.
     */
    for (i = 0, nbufs = 0; i < seqlen; i++) {
        Py_ssize_t itemlen;
        item = PySequence_Fast_GET_ITEM(seq, i);
        if (_getbuffer(item, &buffers[i]) < 0) {
            PyErr_Format(PyExc_TypeError,
                         "sequence item %zd: expected bytes, bytearray, "
                         "or an object with the buffer interface, %.80s found",
                         i, Py_TYPE(item)->tp_name);
            goto error;
        }
        nbufs = i + 1;  /* for error cleanup */
        itemlen = buffers[i].len;
        if (itemlen > PY_SSIZE_T_MAX - sz) {
            PyErr_SetString(PyExc_OverflowError,
                            "join() result is too long");
            goto error;
        }
        sz += itemlen;
        if (i != 0) {
            if (seplen > PY_SSIZE_T_MAX - sz) {
                PyErr_SetString(PyExc_OverflowError,
                                "join() result is too long");
                goto error;
            }
            sz += seplen;
        }
        if (seqlen != PySequence_Fast_GET_SIZE(seq)) {
            PyErr_SetString(PyExc_RuntimeError,
                            "sequence changed size during iteration");
            goto error;
        }
    }

    /* Allocate result space. */
    res = STRINGLIB_NEW(NULL, sz);
    if (res == NULL)
        goto error;

    /* Catenate everything. */
    p = STRINGLIB_STR(res);
    if (!seplen) {
        /* fast path */
        for (i = 0; i < nbufs; i++) {
            Py_ssize_t n = buffers[i].len;
            char *q = buffers[i].buf;
            Py_MEMCPY(p, q, n);
            p += n;
        }
        goto done;
    }
    for (i = 0; i < nbufs; i++) {
        Py_ssize_t n;
        char *q;
        if (i) {
            Py_MEMCPY(p, sepstr, seplen);
            p += seplen;
        }
        n = buffers[i].len;
        q = buffers[i].buf;
        Py_MEMCPY(p, q, n);
        p += n;
    }
    goto done;

error:
    res = NULL;
done:
    Py_DECREF(seq);
    for (i = 0; i < nbufs; i++)
        PyBuffer_Release(&buffers[i]);
    if (buffers != static_buffers)
        PyMem_FREE(buffers);
    return res;
}

#undef NB_STATIC_BUFFERS
'>dkf_loop_exception_range_work Tcl is a high-level, general-purpose, interpreted, dynamic programming language. It was designed with the goal of being very simple but powerful.
summaryrefslogtreecommitdiffstats
path: root/doc/error.n
blob: d61bd7bb529467421186f395f730bba4f7288e83 (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
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1996 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
.so man.macros
.TH error n "" Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
error \- Generate an error
.SH SYNOPSIS
\fBerror \fImessage\fR ?\fIinfo\fR? ?\fIcode\fR?
.BE

.SH DESCRIPTION
.PP
Returns a \fBTCL_ERROR\fR code, which causes command interpretation to be
unwound.  \fIMessage\fR is a string that is returned to the application
to indicate what went wrong.
.PP
The \fB\-errorinfo\fR return option of an interpreter is used
to accumulate a stack trace of what was in progress when an
error occurred; as nested commands unwind,
the Tcl interpreter adds information to the \fB\-errorinfo\fR
return option.  If the \fIinfo\fR argument is present, it is
used to initialize the \fB\-errorinfo\fR return options and
the first increment of unwind information
will not be added by the Tcl interpreter.  
In other
words, the command containing the \fBerror\fR command will not appear
in the stack trace; in its place will be \fIinfo\fR.
Historically, this feature had been most useful in conjunction
with the \fBcatch\fR command:
if a caught error cannot be handled successfully, \fIinfo\fR can be used
to return a stack trace reflecting the original point of occurrence
of the error:
.PP
.CS
catch {...} errMsg
set savedInfo $::errorInfo
\&...
\fBerror\fR $errMsg $savedInfo
.CE
.PP
When working with Tcl 8.5 or later, the following code
should be used instead:
.PP
.CS
catch {...} errMsg options
\&...
return -options $options $errMsg
.CE
.PP
If the \fIcode\fR argument is present, then its value is stored
in the \fB\-errorcode\fR return option.  The \fB\-errorcode\fR
return option is intended to hold a machine-readable description
of the error in cases where such information is available; see
the \fBreturn\fR manual page for information on the proper format
for this option's value.
.SH EXAMPLE
.PP
Generate an error if a basic mathematical operation fails:
.PP
.CS
if {1+2 != 3} {
    \fBerror\fR "something is very wrong with addition"
}
.CE
.SH "SEE ALSO"
catch(n), return(n)
.SH KEYWORDS
error, exception
'\" Local Variables:
'\" mode: nroff
'\" End: