summaryrefslogtreecommitdiffstats
path: root/Python/future.c
blob: d6b653f31593b8fb5e754d3fb8447a0e9da8dc6a (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
#include "Python.h"
#include "Python-ast.h"
#include "node.h"
#include "token.h"
#include "graminit.h"
#include "code.h"
#include "symtable.h"

#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined"
#define ERR_LATE_FUTURE \
"from __future__ imports must occur at the beginning of the file"

static int
future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename)
{
    int i;
    asdl_seq *names;

    assert(s->kind == ImportFrom_kind);

    names = s->v.ImportFrom.names;
    for (i = 0; i < asdl_seq_LEN(names); i++) {
        alias_ty name = (alias_ty)asdl_seq_GET(names, i);
        const char *feature = _PyUnicode_AsString(name->name);
        if (!feature)
            return 0;
        if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_DIVISION) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_PRINT_FUNCTION) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_UNICODE_LITERALS) == 0) {
            continue;
        } else if (strcmp(feature, FUTURE_BARRY_AS_BDFL) == 0) {
            ff->ff_features |= CO_FUTURE_BARRY_AS_BDFL;
        } else if (strcmp(feature, "braces") == 0) {
            PyErr_SetString(PyExc_SyntaxError,
                            "not a chance");
            PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset);
            return 0;
        } else {
            PyErr_Format(PyExc_SyntaxError,
                         UNDEFINED_FUTURE_FEATURE, feature);
            PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset);
            return 0;
        }
    }
    return 1;
}

static int
future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename)
{
    int i, found_docstring = 0, done = 0, prev_line = 0;

    static PyObject *future;
    if (!future) {
        future = PyUnicode_InternFromString("__future__");
        if (!future)
            return 0;
    }

    if (!(mod->kind == Module_kind || mod->kind == Interactive_kind))
        return 1;

    /* A subsequent pass will detect future imports that don't
       appear at the beginning of the file.  There's one case,
       however, that is easier to handle here: A series of imports
       joined by semi-colons, where the first import is a future
       statement but some subsequent import has the future form
       but is preceded by a regular import.
    */


    for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) {
        stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);

        if (done && s->lineno > prev_line)
            return 1;
        prev_line = s->lineno;

        /* The tests below will return from this function unless it is
           still possible to find a future statement.  The only things
           that can precede a future statement are another future
           statement and a doc string.
        */

        if (s->kind == ImportFrom_kind) {
            if (s->v.ImportFrom.module == future) {
                if (done) {
                    PyErr_SetString(PyExc_SyntaxError,
                                    ERR_LATE_FUTURE);
                    PyErr_SyntaxLocationEx(filename, s->lineno, s->col_offset);
                    return 0;
                }
                if (!future_check_features(ff, s, filename))
                    return 0;
                ff->ff_lineno = s->lineno;
            }
            else
                done = 1;
        }
        else if (s->kind == Expr_kind && !found_docstring) {
            expr_ty e = s->v.Expr.value;
            if (e->kind != Str_kind)
                done = 1;
            else
                found_docstring = 1;
        }
        else
            done = 1;
    }
    return 1;
}


PyFutureFeatures *
PyFuture_FromAST(mod_ty mod, const char *filename)
{
    PyFutureFeatures *ff;

    ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures));
    if (ff == NULL) {
        PyErr_NoMemory();
        return NULL;
    }
    ff->ff_features = 0;
    ff->ff_lineno = -1;

    if (!future_parse(ff, mod, filename)) {
        PyObject_Free(ff);
        return NULL;
    }
    return ff;
}
ss="hl com"> in the initial shift state. */ *out++ = 0xdc00 + *in++; argsize--; memset(&mbs, 0, sizeof mbs); continue; } if (*out >= 0xd800 && *out <= 0xdfff) { /* Surrogate character. Escape the original byte sequence with surrogateescape. */ argsize -= converted; while (converted--) *out++ = 0xdc00 + *in++; continue; } /* successfully converted some bytes */ in += converted; argsize -= converted; out++; } #else /* Cannot use C locale for escaping; manually escape as if charset is ASCII (i.e. escape all bytes > 128. This will still roundtrip correctly in the locale's charset, which must be an ASCII superset. */ res = PyMem_Malloc((strlen(arg)+1)*sizeof(wchar_t)); if (!res) goto oom; in = (unsigned char*)arg; out = res; while(*in) if(*in < 128) *out++ = *in++; else *out++ = 0xdc00 + *in++; *out = 0; #endif return res; oom: fprintf(stderr, "out of memory\n"); return NULL; } /* Encode a (wide) character string to the locale encoding with the surrogateescape error handler (characters in range U+DC80..U+DCFF are converted to bytes 0x80..0xFF). This function is the reverse of _Py_char2wchar(). Return a pointer to a newly allocated byte string (use PyMem_Free() to free the memory), or NULL on error (conversion error or memory error). */ char* _Py_wchar2char(const wchar_t *text) { const size_t len = wcslen(text); char *result = NULL, *bytes = NULL; size_t i, size, converted; wchar_t c, buf[2]; /* The function works in two steps: 1. compute the length of the output buffer in bytes (size) 2. outputs the bytes */ size = 0; buf[1] = 0; while (1) { for (i=0; i < len; i++) { c = text[i]; if (c >= 0xdc80 && c <= 0xdcff) { /* UTF-8b surrogate */ if (bytes != NULL) { *bytes++ = c - 0xdc00; size--; } else size++; continue; } else { buf[0] = c; if (bytes != NULL) converted = wcstombs(bytes, buf, size); else converted = wcstombs(NULL, buf, 0); if (converted == (size_t)-1) { if (result != NULL) PyMem_Free(result); return NULL; } if (bytes != NULL) { bytes += converted; size -= converted; } else size += converted; } } if (result != NULL) { *bytes = 0; break; } size += 1; /* nul byte at the end */ result = PyMem_Malloc(size); if (result == NULL) return NULL; bytes = result; } return result; } /* In principle, this should use HAVE__WSTAT, and _wstat should be detected by autoconf. However, no current POSIX system provides that function, so testing for it is pointless. Not sure whether the MS_WINDOWS guards are necessary: perhaps for cygwin/mingw builds? */ #if defined(HAVE_STAT) && !defined(MS_WINDOWS) /* Get file status. Encode the path to the locale encoding. */ int _Py_wstat(const wchar_t* path, struct stat *buf) { int err; char *fname; fname = _Py_wchar2char(path); if (fname == NULL) { errno = EINVAL; return -1; } err = stat(fname, buf); PyMem_Free(fname); return err; } #endif /* Call _wstat() on Windows, or encode the path to the filesystem encoding and call stat() otherwise. Only fill st_mode attribute on Windows. Return 0 on success, -1 on _wstat() / stat() error or (if PyErr_Occurred()) unicode error. */ int _Py_stat(PyObject *path, struct stat *statbuf) { #ifdef MS_WINDOWS int err; struct _stat wstatbuf; err = _wstat(PyUnicode_AS_UNICODE(path), &wstatbuf); if (!err) statbuf->st_mode = wstatbuf.st_mode; return err; #else int ret; PyObject *bytes = PyUnicode_EncodeFSDefault(path); if (bytes == NULL) return -1; ret = stat(PyBytes_AS_STRING(bytes), statbuf); Py_DECREF(bytes); return ret; #endif } /* Open a file. Use _wfopen() on Windows, encode the path to the locale encoding and use fopen() otherwise. */ FILE * _Py_wfopen(const wchar_t *path, const wchar_t *mode) { #ifndef MS_WINDOWS FILE *f; char *cpath; char cmode[10]; size_t r; r = wcstombs(cmode, mode, 10); if (r == (size_t)-1 || r >= 10) { errno = EINVAL; return NULL; } cpath = _Py_wchar2char(path); if (cpath == NULL) return NULL; f = fopen(cpath, cmode); PyMem_Free(cpath); return f; #else return _wfopen(path, mode); #endif } /* Call _wfopen() on Windows, or encode the path to the filesystem encoding and call fopen() otherwise. Return the new file object on success, or NULL if the file cannot be open or (if PyErr_Occurred()) on unicode error */ FILE* _Py_fopen(PyObject *path, const char *mode) { #ifdef MS_WINDOWS wchar_t wmode[10]; int usize; usize = MultiByteToWideChar(CP_ACP, 0, mode, -1, wmode, sizeof(wmode)); if (usize == 0) return NULL; return _wfopen(PyUnicode_AS_UNICODE(path), wmode); #else FILE *f; PyObject *bytes = PyUnicode_EncodeFSDefault(path); if (bytes == NULL) return NULL; f = fopen(PyBytes_AS_STRING(bytes), mode); Py_DECREF(bytes); return f; #endif } #ifdef HAVE_READLINK /* Read value of symbolic link. Encode the path to the locale encoding, decode the result from the locale encoding. */ int _Py_wreadlink(const wchar_t *path, wchar_t *buf, size_t bufsiz) { char *cpath; char cbuf[PATH_MAX]; int res; size_t r1; cpath = _Py_wchar2char(path); if (cpath == NULL) { errno = EINVAL; return -1; } res = (int)readlink(cpath, cbuf, PATH_MAX); PyMem_Free(cpath); if (res == -1) return -1; if (res == PATH_MAX) { errno = EINVAL; return -1; } cbuf[res] = '\0'; /* buf will be null terminated */ r1 = mbstowcs(buf, cbuf, bufsiz); if (r1 == -1) { errno = EINVAL; return -1; } return (int)r1; } #endif #ifdef HAVE_REALPATH /* Return the canonicalized absolute pathname. Encode path to the locale encoding, decode the result from the locale encoding. */ wchar_t* _Py_wrealpath(const wchar_t *path, wchar_t *resolved_path, size_t resolved_path_size) { char *cpath; char cresolved_path[PATH_MAX]; char *res; size_t r; cpath = _Py_wchar2char(path); if (cpath == NULL) { errno = EINVAL; return NULL; } res = realpath(cpath, cresolved_path); PyMem_Free(cpath); if (res == NULL) return NULL; r = mbstowcs(resolved_path, cresolved_path, resolved_path_size); if (r == (size_t)-1 || r >= PATH_MAX) { errno = EINVAL; return NULL; } return resolved_path; } #endif /* Get the current directory. Decode the path from the locale encoding. */ wchar_t* _Py_wgetcwd(wchar_t *buf, size_t size) { #ifdef MS_WINDOWS return _wgetcwd(buf, size); #else char fname[PATH_MAX]; if (getcwd(fname, PATH_MAX) == NULL) return NULL; if (mbstowcs(buf, fname, size) >= size) { errno = ERANGE; return NULL; } return buf; #endif } #endif