1
/**
2
 * This module defines some utility functions for DMD.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_utils.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utils.d
10
 */
11

12
module dmd.utils;
13

14
import core.stdc.string;
15
import dmd.errors;
16
import dmd.globals;
17
import dmd.root.file;
18
import dmd.root.filename;
19
import dmd.root.outbuffer;
20
import dmd.root.string;
21

22

23
/**
24
 * Normalize path by turning forward slashes into backslashes
25
 *
26
 * Params:
27
 *   src = Source path, using unix-style ('/') path separators
28
 *
29
 * Returns:
30
 *   A newly-allocated string with '/' turned into backslashes
31
 */
32
const(char)* toWinPath(const(char)* src)
33
{
34 0
    if (src is null)
35 0
        return null;
36 0
    char* result = strdup(src);
37 0
    char* p = result;
38 0
    while (*p != '\0')
39
    {
40 0
        if (*p == '/')
41 0
            *p = '\\';
42 0
        p++;
43
    }
44 0
    return result;
45
}
46

47

48
/**
49
 * Reads a file, terminate the program on error
50
 *
51
 * Params:
52
 *   loc = The line number information from where the call originates
53
 *   filename = Path to file
54
 */
55
FileBuffer readFile(Loc loc, const(char)* filename)
56
{
57 1
    return readFile(loc, filename.toDString());
58
}
59

60
/// Ditto
61
FileBuffer readFile(Loc loc, const(char)[] filename)
62
{
63 1
    auto result = File.read(filename);
64 1
    if (!result.success)
65
    {
66 0
        error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr);
67 0
        fatal();
68
    }
69 1
    return FileBuffer(result.extractSlice());
70
}
71

72

73
/**
74
 * Writes a file, terminate the program on error
75
 *
76
 * Params:
77
 *   loc = The line number information from where the call originates
78
 *   filename = Path to file
79
 *   data = Full content of the file to be written
80
 */
81
extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
82
{
83 1
    ensurePathToNameExists(Loc.initial, filename);
84 1
    if (!File.write(filename, data))
85
    {
86 0
        error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
87 0
        fatal();
88
    }
89
}
90

91

92
/**
93
 * Ensure the root path (the path minus the name) of the provided path
94
 * exists, and terminate the process if it doesn't.
95
 *
96
 * Params:
97
 *   loc = The line number information from where the call originates
98
 *   name = a path to check (the name is stripped)
99
 */
100
void ensurePathToNameExists(Loc loc, const(char)[] name)
101
{
102 1
    const char[] pt = FileName.path(name);
103 1
    if (pt.length)
104
    {
105 1
        if (!FileName.ensurePathExists(pt))
106
        {
107 0
            error(loc, "cannot create directory %*.s", cast(int) pt.length, pt.ptr);
108 0
            fatal();
109
        }
110
    }
111 1
    FileName.free(pt.ptr);
112
}
113

114

115
/**
116
 * Takes a path, and escapes '(', ')' and backslashes
117
 *
118
 * Params:
119
 *   buf = Buffer to write the escaped path to
120
 *   fname = Path to escape
121
 */
122
void escapePath(OutBuffer* buf, const(char)* fname)
123
{
124 1
    while (1)
125
    {
126 1
        switch (*fname)
127
        {
128 1
        case 0:
129 1
            return;
130 0
        case '(':
131 0
        case ')':
132 0
        case '\\':
133 0
            buf.writeByte('\\');
134 0
            goto default;
135 1
        default:
136 1
            buf.writeByte(*fname);
137 1
            break;
138
        }
139 1
        fname++;
140
    }
141
}
142

143
/**
144
 * Convert string to integer.
145
 *
146
 * Params:
147
 *  T = Type of integer to parse
148
 *  val = Variable to store the result in
149
 *  p = slice to start of string digits
150
 *  max = max allowable value (inclusive), defaults to `T.max`
151
 *
152
 * Returns:
153
 *  `false` on error, `true` on success
154
 */
155
bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max)
156
    @safe pure @nogc nothrow
157
{
158
    import core.checkedint : mulu, addu, muls, adds;
159

160
    // mul* / add* doesn't support types < int
161
    static if (T.sizeof < int.sizeof)
162
    {
163 1
        int value;
164
        alias add = adds;
165
        alias mul = muls;
166
    }
167
    // unsigned
168
    else static if (T.min == 0)
169
    {
170 1
        T value;
171
        alias add = addu;
172
        alias mul = mulu;
173
    }
174
    else
175
    {
176
        T value;
177
        alias add = adds;
178
        alias mul = muls;
179
    }
180

181 1
    bool overflow;
182 1
    foreach (char c; p)
183
    {
184 1
        if (c > '9' || c < '0')
185 1
            return false;
186 1
        value = mul(value, 10, overflow);
187 1
        value = add(value, uint(c - '0'), overflow);
188
    }
189
    // If it overflows, value must be > to `max` (since `max` is `T`)
190 1
    val = cast(T) value;
191 1
    return !overflow && value <= max;
192
}
193

194
///
195
@safe pure nothrow @nogc unittest
196
{
197
    byte b;
198
    ubyte ub;
199
    short s;
200
    ushort us;
201
    int i;
202
    uint ui;
203
    long l;
204
    ulong ul;
205

206
    assert(b.parseDigits("42") && b  == 42);
207
    assert(ub.parseDigits("42") && ub == 42);
208

209
    assert(s.parseDigits("420") && s  == 420);
210
    assert(us.parseDigits("42000") && us == 42_000);
211

212
    assert(i.parseDigits("420000") && i  == 420_000);
213
    assert(ui.parseDigits("420000") && ui == 420_000);
214

215
    assert(l.parseDigits("42000000000") && l  == 42_000_000_000);
216
    assert(ul.parseDigits("82000000000") && ul == 82_000_000_000);
217

218
    assert(!b.parseDigits(ubyte.max.stringof));
219
    assert(!b.parseDigits("WYSIWYG"));
220
    assert(!b.parseDigits("-42"));
221
    assert(!b.parseDigits("200"));
222
    assert(ub.parseDigits("200") && ub == 200);
223
    assert(i.parseDigits(int.max.stringof) && i == int.max);
224
    assert(i.parseDigits("420", 500) && i == 420);
225
    assert(!i.parseDigits("420", 400));
226
}

Read our documentation on viewing source code .

Loading