├── .editorconfig ├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── LICENSE.txt ├── README.md ├── dmdsamples ├── .gitignore ├── all.sh ├── build.bat ├── chello.d ├── clean.bat ├── d2html.d ├── d2html.kwd ├── dclient.d ├── dhry.d ├── dserver.d ├── dserver64.def ├── hello.d ├── htmlget.d ├── listener.d ├── mydll │ ├── build.bat │ ├── dll.d │ ├── mydll.d │ ├── mydll.def │ ├── mydll.di │ └── test.d ├── pi.d ├── posix.mak ├── sieve.d ├── wc.d ├── wc2.d ├── win32.mak ├── winsamp.d └── winsamp.def ├── dub.sdl ├── examples └── hello-from-the-dead │ ├── dub.sdl │ └── source │ └── app.d ├── posix.mak ├── src └── undead │ ├── bitarray.d │ ├── cstream.d │ ├── date.d │ ├── datebase.d │ ├── dateparse.d │ ├── doformat.d │ ├── internal │ └── file.d │ ├── metastrings.d │ ├── regexp.d │ ├── signals.d │ ├── socketstream.d │ ├── stream.d │ ├── string.d │ ├── utf.d │ └── xml.d ├── win32.mak └── win64.mak /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{c,h,d,di,dd}] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 4 8 | trim_trailing_whitespace = true 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # Cross platform GitHub Actions CI for undeaD 2 | 3 | name: Testsuite 4 | 5 | # Only triggers on pushes to master & stable, as well as PR to master and stable 6 | # Sometimes reverts appear in the upstream repository (e.g. when the revert button 7 | # is clicked by a contributor with commit access), this should be tested as PR). 8 | # 9 | # Also note that Github actions does not retrigger on target branch changes, 10 | # hence the check on push. 11 | on: 12 | pull_request: 13 | branches: 14 | - master 15 | - stable 16 | push: 17 | branches: 18 | - master 19 | - stable 20 | # Use this branch name in your fork to test changes 21 | - github-actions 22 | 23 | jobs: 24 | main: 25 | name: Run 26 | strategy: 27 | # Default, disable if you want to debug 28 | fail-fast: false 29 | matrix: 30 | # Latest stable version, update at will 31 | os: [ macOS-11, ubuntu-20.04, windows-2019 ] 32 | dc: [ dmd-latest, ldc-latest, dmd-master, ldc-master ] 33 | include: 34 | - os: ubuntu-20.04 35 | dc: gdc-10 36 | 37 | runs-on: ${{ matrix.os }} 38 | steps: 39 | 40 | - name: Install D compiler - ${{ matrix.dc }} 41 | if: ${{ matrix.dc != 'gdc-10' }} 42 | uses: dlang-community/setup-dlang@v1 43 | with: 44 | compiler: ${{ matrix.dc }} 45 | 46 | - name: Install latest DMD (for dub) 47 | if: ${{ matrix.dc == 'gdc-10' }} 48 | uses: dlang-community/setup-dlang@v1 49 | with: 50 | compiler: dmd-latest 51 | 52 | - name: Install GDC via apt-get 53 | if: ${{ matrix.dc == 'gdc-10' }} 54 | run: | 55 | sudo apt-get update 56 | sudo apt-get install ${{ matrix.dc }} -y 57 | 58 | - name: Checkout 59 | uses: actions/checkout@v2 60 | 61 | # avoids issue with setup-dlang setting DC 62 | - name: 'Build and Test' 63 | if: ${{ matrix.dc == 'gdc-10' }} 64 | shell: bash 65 | run: | 66 | gdc-10 --version 67 | dub build --compiler=gdc-10 68 | dub test --compiler=gdc-10 -v 69 | 70 | - name: 'Build and Test' 71 | if: ${{ matrix.dc != 'gdc-10' }} 72 | shell: bash 73 | run: | 74 | $DC --version 75 | dub build --compiler=$DC 76 | dub test --compiler=$DC -v 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .B* 2 | *.bak 3 | *.lst 4 | 5 | # Object files 6 | *.o 7 | *.ko 8 | *.obj 9 | *.elf 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Libraries 16 | *.lib 17 | *.a 18 | *.la 19 | *.lo 20 | 21 | # Shared objects (inc. Windows DLLs) 22 | *.dll 23 | *.so 24 | *.so.* 25 | *.dylib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | *.i*86 32 | *.x86_64 33 | *.hex 34 | 35 | # Extra dirs/build files 36 | bin 37 | obj 38 | .dub 39 | .vs 40 | undead.sln 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | undeaD 2 | ====== 3 | 4 | Need an obsolete Phobos module? Here they are, back from the dead and upgraded to work with the latest D 5 | 6 | Current modules included: 7 | 8 | * std.bitarray 9 | * std.date 10 | * std.datebase 11 | * std.dateparse 12 | * std.regexp 13 | * std.signals 14 | * std.stream and friends 15 | * std.xml 16 | 17 | Some individual functions have been moved here rather than full Phobos modules. They are 18 | 19 | * undead.doformat: Contains the `doFormat` function from std.format 20 | * undead.string: Contains regex style pattern matching functions from std.string 21 | 22 | The dmdsamples folder contains a list of code samples which used to be located 23 | in the dmd installation directory, but which have not been kept up to date, so 24 | they are now located here as well. 25 | 26 | -------------------------------------------------------------------------------- /dmdsamples/.gitignore: -------------------------------------------------------------------------------- 1 | *.d.htm 2 | *.exe 3 | chello 4 | dclient 5 | dserver 6 | d2html 7 | dhry 8 | hello 9 | htmlget 10 | listener 11 | pi 12 | sieve 13 | wc 14 | wc2 15 | winsamp 16 | -------------------------------------------------------------------------------- /dmdsamples/all.sh: -------------------------------------------------------------------------------- 1 | 2 | # Little shell script to compile, link, and run all the samples. 3 | # Use dmd\windows\bin\shell.exe to execute. 4 | 5 | DMD=..\..\windows\bin\dmd 6 | DFLAGS= 7 | CLEAN=clean.bat 8 | 9 | 10 | 11 | #~ $(DMD) chello $(DFLAGS) # which compilation flags? 12 | #~ chello 13 | 14 | $(DMD) d2html $(DFLAGS) 15 | d2html d2html.d 16 | 17 | $(DMD) dhry $(DFLAGS) 18 | dhry 19 | 20 | $(DMD) hello $(DFLAGS) 21 | hello 22 | 23 | #~ $(DMD) htmlget $(DFLAGS) # broken 24 | 25 | #~ $(DMD) listener $(DFLAGS) # broken 26 | 27 | 28 | $(DMD) pi $(DFLAGS) 29 | pi 1000 30 | 31 | $(DMD) sieve $(DFLAGS) 32 | sieve 33 | 34 | $(DMD) wc $(DFLAGS) 35 | wc wc.d 36 | 37 | $(DMD) wc2 $(DFLAGS) 38 | wc2 wc2.d 39 | 40 | $(DMD) winsamp gdi32.lib winsamp.def 41 | winsamp 42 | 43 | # COM client/server example 44 | $(DMD) dserver.d chello.d dserver.def advapi32.lib ole32.lib user32.lib 45 | # dclient will fail unless run with administrator rights 46 | $(DMD) dclient $(DFLAGS) ole32.lib uuid.lib 47 | dclient 48 | 49 | $(CLEAN) 50 | -------------------------------------------------------------------------------- /dmdsamples/build.bat: -------------------------------------------------------------------------------- 1 | ..\..\windows\bin\shell all.sh 2 | -------------------------------------------------------------------------------- /dmdsamples/chello.d: -------------------------------------------------------------------------------- 1 | 2 | /* Server for IHello 3 | * Heavily modified from: 4 | */ 5 | /* 6 | * SELFREG.CPP 7 | * Server Self-Registrtation Utility, Chapter 5 8 | * 9 | * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 10 | * 11 | * Kraig Brockschmidt, Microsoft 12 | * Internet : kraigb@microsoft.com 13 | * Compuserve: >INTERNET:kraigb@microsoft.com 14 | */ 15 | 16 | // From an example from "Inside OLE" Copyright Microsoft 17 | 18 | import core.stdc.stdio; 19 | import core.stdc.stdlib; 20 | import std.string; 21 | import core.sys.windows.com; 22 | import core.sys.windows.windef; 23 | 24 | GUID CLSID_Hello = { 0x30421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46] }; 25 | GUID IID_IHello = { 0x00421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46] }; 26 | 27 | interface IHello : IUnknown 28 | { 29 | extern (Windows) : 30 | int Print(); 31 | } 32 | 33 | // Type for an object-destroyed callback 34 | alias void function() PFNDESTROYED; 35 | 36 | /* 37 | * The class definition for an object that singly implements 38 | * IHello in D. 39 | */ 40 | class CHello : ComObject, IHello 41 | { 42 | protected: 43 | IUnknown m_pUnkOuter; // Controlling unknown 44 | 45 | PFNDESTROYED m_pfnDestroy; // To call on closure 46 | 47 | /* 48 | * pUnkOuter LPUNKNOWN of a controlling unknown. 49 | * pfnDestroy PFNDESTROYED to call when an object 50 | * is destroyed. 51 | */ 52 | public this(IUnknown pUnkOuter, PFNDESTROYED pfnDestroy) 53 | { 54 | m_pUnkOuter = pUnkOuter; 55 | m_pfnDestroy = pfnDestroy; 56 | } 57 | 58 | ~this() 59 | { 60 | printf("CHello.~this()\n"); 61 | } 62 | 63 | extern (Windows) : 64 | /* 65 | * Performs any initialization of a CHello that's prone to failure 66 | * that we also use internally before exposing the object outside. 67 | * Return Value: 68 | * BOOL true if the function is successful, 69 | * false otherwise. 70 | */ 71 | 72 | public: 73 | BOOL Init() 74 | { 75 | printf("CHello.Init()\n"); 76 | return true; 77 | } 78 | 79 | public: 80 | override HRESULT QueryInterface(const (IID)*riid, LPVOID *ppv) 81 | { 82 | printf("CHello.QueryInterface()\n"); 83 | 84 | if (IID_IUnknown == *riid) 85 | *ppv = cast(void*) cast(IUnknown) this; 86 | else if (IID_IHello == *riid) 87 | *ppv = cast(void*) cast(IHello) this; 88 | else 89 | { 90 | *ppv = null; 91 | return E_NOINTERFACE; 92 | } 93 | 94 | AddRef(); 95 | return NOERROR; 96 | } 97 | 98 | override ULONG Release() 99 | { 100 | printf("CHello.Release()\n"); 101 | 102 | if (0 != --count) 103 | return count; 104 | 105 | /* 106 | * Tell the housing that an object is going away so it can 107 | * shut down if appropriate. 108 | */ 109 | printf("CHello Destroy()\n"); 110 | 111 | if (m_pfnDestroy) 112 | (*m_pfnDestroy)(); 113 | 114 | // delete this; 115 | return 0; 116 | } 117 | 118 | // IHello members 119 | override HRESULT Print() 120 | { 121 | printf("CHello.Print()\n"); 122 | return NOERROR; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /dmdsamples/clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal EnableDelayedExpansion 3 | del *.obj 4 | del *.res 5 | -------------------------------------------------------------------------------- /dmdsamples/d2html.d: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2001 3 | * Pavel "EvilOne" Minayev 4 | * 5 | * Permission to use, copy, modify, distribute and sell this software 6 | * and its documentation for any purpose is hereby granted without fee, 7 | * provided that the above copyright notice appear in all copies and 8 | * that both that copyright notice and this permission notice appear 9 | * in supporting documentation. Author makes no representations about 10 | * the suitability of this software for any purpose. It is provided 11 | * "as is" without express or implied warranty. 12 | */ 13 | 14 | import core.stdc.stdio; 15 | 16 | import std.conv; 17 | import std.string; 18 | import std.stdio; 19 | import std.ascii; 20 | import std.file; 21 | 22 | // colors for syntax highlighting, default values are 23 | // my preferences in Microsoft Visual Studio editor 24 | enum Colors 25 | { 26 | keyword = "0000FF", 27 | number = "008000", 28 | astring = "000080", 29 | comment = "808080" 30 | } 31 | 32 | enum tabsize = 4; // number of spaces in tab 33 | bool[string] keywords; 34 | 35 | 36 | void main(string[] args) 37 | { 38 | // need help? 39 | if (args.length < 2 || args.length > 3) 40 | { 41 | printf("D to HTML converter\n" ~ 42 | "Usage: D2HTML .d [.htm]\n"); 43 | return; 44 | } 45 | 46 | // auto-name output file 47 | if (args.length == 2) 48 | args ~= args[1] ~ ".htm"; 49 | 50 | // load keywords 51 | assert("d2html.kwd".exists, "file d2html.kwd does not exist"); 52 | auto kwd = File("d2html.kwd"); 53 | foreach (word; kwd.byLine()) 54 | keywords[word.idup] = true; 55 | kwd.close(); 56 | 57 | // open input and output files 58 | auto src = File(args[1]); 59 | auto dst = File(args[2], "w"); 60 | 61 | // write HTML header 62 | dst.writeln("" ~ args[1] ~ ""); 63 | dst.writeln("
");
 64 | 
 65 |     // the main part is wrapped into try..catch block because
 66 |     // when end of file is reached, an exception is raised;
 67 |     // so we can omit any checks for EOF inside this block...
 68 |     try
 69 |     {
 70 |         static char readc(ref File src)
 71 |         {
 72 |             while (true)
 73 |             {
 74 |                 if (src.eof())
 75 |                     throw new Exception("");
 76 |                 char c;
 77 |                 src.readf("%c", &c);
 78 |                 if (c != '\r' && c != 0xFF)
 79 |                     return c;
 80 |             }
 81 |         }
 82 | 
 83 |         ulong linestart = 0;             // for tabs
 84 |         char c;
 85 | 
 86 |         c = readc(src);
 87 | 
 88 |         while (true)
 89 |         {
 90 |             if (isWhite(c))                     // whitespace
 91 |             {
 92 |                 do
 93 |                 {
 94 |                     if (c == 9)
 95 |                     {
 96 |                         // expand tabs to spaces
 97 |                         immutable spaces = tabsize -
 98 |                                      (src.tell() - linestart) % tabsize;
 99 | 
100 |                         for (int i = 0; i < spaces; i++)
101 |                             dst.write(" ");
102 | 
103 |                         linestart = src.tell() - tabsize + 1;
104 |                     }
105 |                     else
106 |                     {
107 |                         // reset line start on newline
108 |                         if (c == 10 || c == 13)
109 |                             linestart = src.tell() + 1;
110 | 
111 |                         dst.write(c);
112 |                     }
113 | 
114 |                     c = readc(src);
115 |                 } while (isWhite(c));
116 |             }
117 |             else if (isAlpha(c))                // keyword or identifier
118 |             {
119 |                 string token;
120 | 
121 |                 do
122 |                 {
123 |                     token ~= c;
124 |                     c = readc(src);
125 |                 } while (isAlpha(c) || isDigit(c));
126 | 
127 |                 if (token in keywords)                   // keyword
128 |                     dst.write("" ~ token ~ "");
130 |                 else                    // simple identifier
131 |                     dst.write(token);
132 |             }
133 |             else if (c == '0')                  // binary, octal or hexadecimal number
134 |             {
135 |                 dst.write("");
136 |                 dst.write(c);
137 |                 c = readc(src);
138 | 
139 |                 if (c == 'X' || c == 'x')                       // hexadecimal
140 |                 {
141 |                     dst.write(c);
142 |                     c = readc(src);
143 | 
144 |                     while (isHexDigit(c)) {
145 |                         dst.write(c);
146 |                         c = readc(src);
147 |                     }
148 | 
149 |                     // TODO: add support for hexadecimal floats
150 |                 }
151 |                 else if (c == 'B' || c == 'b')                  // binary
152 |                 {
153 |                     dst.write(c);
154 |                     c = readc(src);
155 | 
156 |                     while (c == '0' || c == '1') {
157 |                         dst.write(c);
158 |                         c = readc(src);
159 |                     }
160 |                 }
161 |                 else                    // octal
162 |                 {
163 |                     do
164 |                     {
165 |                         dst.write(c);
166 |                         c = readc(src);
167 |                     } while (isOctalDigit(c));
168 |                 }
169 | 
170 |                 dst.write("");
171 |             }
172 |             else if (c == '#')                // hash
173 |             {
174 |                 dst.write(c);
175 |                 c = readc(src);
176 |             }
177 |             else if (c == '\\')                // backward slash
178 |             {
179 |                 dst.write(c);
180 |                 c = readc(src);
181 |             }
182 |             else if (isDigit(c))                // decimal number
183 |             {
184 |                 dst.write("");
185 | 
186 |                 // integral part
187 |                 do
188 |                 {
189 |                     dst.write(c);
190 |                     c = readc(src);
191 |                 } while (isDigit(c));
192 | 
193 |                 // fractional part
194 |                 if (c == '.')
195 |                 {
196 |                     dst.write(c);
197 |                     c = readc(src);
198 | 
199 |                     while (isDigit(c))
200 |                     {
201 |                         dst.write(c);
202 |                         c = readc(src);
203 |                     }
204 |                 }
205 | 
206 |                 // scientific notation
207 |                 if (c == 'E' || c == 'e')
208 |                 {
209 |                     dst.write(c);
210 |                     c = readc(src);
211 | 
212 |                     if (c == '+' || c == '-')
213 |                     {
214 |                         dst.write(c);
215 |                         c = readc(src);
216 |                     }
217 | 
218 |                     while (isDigit(c))
219 |                     {
220 |                         dst.write(c);
221 |                         c = readc(src);
222 |                     }
223 |                 }
224 | 
225 |                 // suffices
226 |                 while (c == 'U' || c == 'u' || c == 'L' ||
227 |                        c == 'l' || c == 'F' || c == 'f')
228 |                 {
229 |                     dst.write(c);
230 |                     c = readc(src);
231 |                 }
232 | 
233 |                 dst.write("");
234 |             }
235 |             else if (c == '\'')                 // string without escape sequences
236 |             {
237 |                 dst.write("");
238 | 
239 |                 do
240 |                 {
241 |                     if (c == '<')                       // special symbol in HTML
242 |                         dst.write("<");
243 |                     else
244 |                         dst.write(c);
245 | 
246 |                     c = readc(src);
247 |                 } while (c != '\'');
248 |                 dst.write(c);
249 |                 c = readc(src);
250 |                 dst.write("");
251 |             }
252 |             else if (c == 34)                   // string with escape sequences
253 |             {
254 |                 dst.write("");
255 |                 char prev;                      // used to handle \" properly
256 | 
257 |                 do
258 |                 {
259 |                     if (c == '<')                       // special symbol in HTML
260 |                         dst.write("<");
261 |                     else
262 |                         dst.write(c);
263 | 
264 |                     prev = c;
265 |                     c = readc(src);
266 |                 } while (!(c == 34 && prev != '\\'));                   // handle \"
267 |                 dst.write(c);
268 |                 c = readc(src);
269 |                 dst.write("");
270 |             }
271 |             else if (isPunctuation(c))          // either operator or comment
272 |             {
273 |                 if (c == '<')                   // special symbol in HTML
274 |                 {
275 |                     dst.write("<");
276 |                     c = readc(src);
277 |                 }
278 |                 else if (c == '/')                      // could be a comment...
279 |                 {
280 |                     c = readc(src);
281 | 
282 |                     if (c == '/')                       // single-line one
283 |                     {
284 |                         dst.write("/");
285 | 
286 |                         while (c != 10)
287 |                         {
288 |                             if (c == '<')                               // special symbol in HTML
289 |                                 dst.write("<");
290 |                             else if (c == 9)
291 |                             {
292 |                                 // expand tabs
293 |                                 immutable spaces2 = tabsize -
294 |                                               (src.tell() - linestart) % tabsize;
295 | 
296 |                                 for (int i2 = 0; i2 < spaces2; i2++)
297 |                                     dst.write(" ");
298 | 
299 |                                 linestart = src.tell() - tabsize + 1;
300 |                             }
301 |                             else
302 |                                 dst.write(c);
303 | 
304 |                             c = readc(src);
305 |                         }
306 | 
307 |                         dst.write("");
308 |                     }
309 |                     else if (c == '*')                          // multi-line one
310 |                     {
311 |                         dst.write("/");
312 |                         char prev2;
313 | 
314 |                         do
315 |                         {
316 |                             if (c == '<')                               // special symbol in HTML
317 |                                 dst.write("<");
318 |                             else if (c == 9)
319 |                             {
320 |                                 // expand tabs
321 |                                 immutable spaces3 = tabsize -
322 |                                               (src.tell() - linestart) % tabsize;
323 | 
324 |                                 for (int i3 = 0; i3 < spaces3; i3++)
325 |                                     dst.write(" ");
326 | 
327 |                                 linestart = src.tell() - tabsize + 1;
328 |                             }
329 |                             else
330 |                             {
331 |                                 // reset line start on newline
332 |                                 if (c == 10 || c == 13)
333 |                                     linestart = src.tell() + 1;
334 | 
335 |                                 dst.write(c);
336 |                             }
337 | 
338 |                             prev2 = c;
339 |                             c = readc(src);
340 |                         } while (!(c == '/' && prev2 == '*'));
341 |                         dst.write(c);
342 |                         dst.write("");
343 |                         c = readc(src);
344 |                     }
345 |                     else                        // just an operator
346 |                         dst.write(cast(char) '/');
347 |                 }
348 |                 else                    // just an operator
349 |                 {
350 |                     dst.write(c);
351 |                     c = readc(src);
352 |                 }
353 |             }
354 |             else
355 |             {
356 |                 // whatever it is, it's not a valid D token
357 |                 throw new Error("unrecognized token " ~ c);
358 |                 //~ break;
359 |             }
360 |         }
361 |     }
362 | 
363 |     // if end of file is reached and we try to read something
364 |     // with typed read(), a ReadError is thrown; in our case,
365 |     // this means that job is successfully done
366 |     catch (Exception e)
367 |     {
368 |         // write HTML footer
369 |         dst.writeln("
"); 370 | } 371 | 372 | return; 373 | } 374 | -------------------------------------------------------------------------------- /dmdsamples/d2html.kwd: -------------------------------------------------------------------------------- 1 | property 2 | abstract 3 | alias 4 | align 5 | asm 6 | assert 7 | auto 8 | body 9 | bool 10 | break 11 | byte 12 | case 13 | cast 14 | catch 15 | cdouble 16 | cent 17 | cfloat 18 | char 19 | class 20 | const 21 | continue 22 | creal 23 | dchar 24 | dstring 25 | debug 26 | default 27 | delegate 28 | delete 29 | deprecated 30 | do 31 | double 32 | else 33 | enum 34 | export 35 | extern 36 | false 37 | final 38 | finally 39 | float 40 | for 41 | foreach 42 | foreach_reverse 43 | function 44 | goto 45 | idouble 46 | if 47 | ifloat 48 | immutable 49 | import 50 | in 51 | inout 52 | int 53 | interface 54 | invariant 55 | ireal 56 | is 57 | lazy 58 | long 59 | macro 60 | mixin 61 | module 62 | new 63 | nothrow 64 | null 65 | out 66 | override 67 | package 68 | pragma 69 | private 70 | protected 71 | public 72 | pure 73 | real 74 | ref 75 | return 76 | scope 77 | shared 78 | short 79 | size_t 80 | static 81 | string 82 | struct 83 | super 84 | switch 85 | synchronized 86 | template 87 | this 88 | throw 89 | true 90 | try 91 | typedef 92 | typeid 93 | typeof 94 | ubyte 95 | ucent 96 | uint 97 | ulong 98 | union 99 | unittest 100 | ushort 101 | version 102 | void 103 | volatile 104 | wchar 105 | wstring 106 | while 107 | with 108 | __FILE__ 109 | __LINE__ 110 | __gshared 111 | __thread 112 | __traits 113 | const_cast 114 | dynamic_cast 115 | explicit 116 | friend 117 | inline 118 | mutable 119 | namespace 120 | operator 121 | register 122 | reinterpret_cast 123 | restrict 124 | signed 125 | sizeof 126 | static_cast 127 | typename 128 | unsigned 129 | using 130 | virtual 131 | int8_t 132 | uint8_t 133 | int16_t 134 | uint16_t 135 | int32_t 136 | uint32_t 137 | int64_t 138 | uint64_t 139 | int_least8_t 140 | uint_least8_t 141 | int_least16_t 142 | uint_least16_t 143 | int_least32_t 144 | uint_least32_t 145 | int_least64_t 146 | uint_least64_t 147 | int_fast8_t 148 | uint_fast8_t 149 | int_fast16_t 150 | uint_fast16_t 151 | int_fast32_t 152 | uint_fast32_t 153 | int_fast64_t 154 | uint_fast64_t 155 | intptr_t 156 | uintptr_t 157 | intmax_t 158 | uintmax_t 159 | wint_t 160 | wchar_t 161 | wctrans_t 162 | time_t 163 | and 164 | and_eq 165 | bitand 166 | bitor 167 | compl 168 | not 169 | not_eq 170 | or 171 | or_eq 172 | xor 173 | xor_eq 174 | wctype_tcomplex 175 | imaginary 176 | _Complex 177 | _Imaginary 178 | _Bool 179 | _Pragma 180 | -------------------------------------------------------------------------------- /dmdsamples/dclient.d: -------------------------------------------------------------------------------- 1 | 2 | /* Client for IHello 3 | * Heavily modified from: 4 | */ 5 | /* 6 | * SELFREG.CPP 7 | * Server Self-Registrtation Utility, Chapter 5 8 | * 9 | * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 10 | * 11 | * Kraig Brockschmidt, Microsoft 12 | * Internet : kraigb@microsoft.com 13 | * Compuserve: >INTERNET:kraigb@microsoft.com 14 | */ 15 | 16 | import core.stdc.stdio; 17 | import core.stdc.stdlib; 18 | import core.sys.windows.com; 19 | import core.sys.windows.winbase; 20 | import core.sys.windows.windef; 21 | 22 | GUID CLSID_Hello = { 0x30421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46] }; 23 | GUID IID_IHello = { 0x00421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46] }; 24 | 25 | interface IHello : IUnknown 26 | { 27 | extern (Windows) : 28 | int Print(); 29 | } 30 | 31 | int main() 32 | { 33 | DWORD dwVer; 34 | HRESULT hr; 35 | IHello pIHello; 36 | 37 | // Make sure COM is the right version 38 | dwVer = CoBuildVersion(); 39 | 40 | if (rmm != HIWORD(dwVer)) 41 | { 42 | printf("Incorrect OLE 2 version number\n"); 43 | return EXIT_FAILURE; 44 | } 45 | 46 | hr=CoInitialize(null); // Initialize OLE 47 | 48 | if (FAILED(hr)) 49 | { 50 | printf("OLE 2 failed to initialize\n"); 51 | return EXIT_FAILURE; 52 | } 53 | 54 | printf("OLE 2 initialized\n"); 55 | 56 | if (dll_regserver("dserver.dll", 1) == 0) 57 | { 58 | printf("server registered\n"); 59 | hr=CoCreateInstance(&CLSID_Hello, null, CLSCTX_ALL, &IID_IHello, cast(void**)&pIHello); 60 | 61 | if (FAILED(hr)) 62 | { 63 | printf("Failed to create object x%x\n", hr); 64 | } 65 | else 66 | { 67 | printf("Object created, calling IHello.Print(), IHello = %p\n", pIHello); 68 | 69 | // fflush(stdout); 70 | pIHello.Print(); 71 | pIHello.Release(); 72 | } 73 | 74 | CoFreeUnusedLibraries(); 75 | 76 | if (dll_regserver("dserver.dll", 0)) 77 | printf("server unregister failed\n"); 78 | } 79 | else 80 | printf("server registration failed\n"); 81 | 82 | // Only call this if CoInitialize worked 83 | CoUninitialize(); 84 | return EXIT_SUCCESS; 85 | } 86 | 87 | /************************************** 88 | * Register/unregister a DLL server. 89 | * Input: 90 | * flag !=0: register 91 | * ==0: unregister 92 | * Returns: 93 | * 0 success 94 | * !=0 failure 95 | */ 96 | 97 | extern (Windows) alias HRESULT function() pfn_t; 98 | 99 | int dll_regserver(const (char) *dllname, int flag) 100 | { 101 | char *fn = flag ? cast(char*) "DllRegisterServer" 102 | : cast(char*) "DllUnregisterServer"; 103 | int result = 1; 104 | pfn_t pfn; 105 | HINSTANCE hMod; 106 | 107 | if (SUCCEEDED(CoInitialize(null))) 108 | { 109 | hMod=LoadLibraryA(dllname); 110 | printf("hMod = %p\n", hMod); 111 | 112 | if (hMod) 113 | { 114 | printf("LoadLibraryA() %s\n", (flag ? "registered".ptr : "unregistered".ptr)); 115 | pfn = cast(pfn_t) GetProcAddress(hMod, fn); 116 | printf("pfn = %p, fn = '%s'\n", pfn, fn); 117 | 118 | if (pfn && SUCCEEDED((*pfn)())) 119 | { 120 | printf("successfully called %s\n", fn); 121 | result = 0; 122 | } 123 | 124 | printf("CoFreeLibrary()\n"); 125 | CoFreeLibrary(hMod); 126 | printf("CoUninitialize()\n"); 127 | CoUninitialize(); 128 | } 129 | } 130 | 131 | return result; 132 | } 133 | -------------------------------------------------------------------------------- /dmdsamples/dhry.d: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ************************************************************************* 4 | * 5 | * "DHRYSTONE" Benchmark Program 6 | * ----------------------------- 7 | * 8 | * Version: C, Version 2.1 9 | * 10 | * File: dhry.h (part 1 of 3) 11 | * 12 | * Date: May 25, 1988 13 | * 14 | * Author: Reinhold P. Weicker 15 | * Siemens Nixdorf Inf. Syst. 16 | * STM OS 32 17 | * Otto-Hahn-Ring 6 18 | * W-8000 Muenchen 83 19 | * Germany 20 | * Phone: [+49]-89-636-42436 21 | * (8-17 Central European Time) 22 | * UUCP: weicker@ztivax.uucp@unido.uucp 23 | * Internet: weicker@ztivax.siemens.com 24 | * 25 | * Original Version (in Ada) published in 26 | * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), 27 | * pp. 1013 - 1030, together with the statistics 28 | * on which the distribution of statements etc. is based. 29 | * 30 | * In this C version, the following C library functions are 31 | * used: 32 | * - strcpy, strcmp (inside the measurement loop) 33 | * - printf, scanf (outside the measurement loop) 34 | * 35 | * Collection of Results: 36 | * Reinhold Weicker (address see above) and 37 | * 38 | * Rick Richardson 39 | * PC Research. Inc. 40 | * 94 Apple Orchard Drive 41 | * Tinton Falls, NJ 07724 42 | * Phone: (201) 834-1378 (9-17 EST) 43 | * UUCP: ...!uunet!pcrat!rick 44 | * 45 | * Please send results to Rick Richardson and/or Reinhold Weicker. 46 | * Complete information should be given on hardware and software 47 | * used. Hardware information includes: Machine type, CPU, type and 48 | * size of caches; for microprocessors: clock frequency, memory speed 49 | * (number of wait states). Software information includes: Compiler 50 | * (and runtime library) manufacturer and version, compilation 51 | * switches, OS version. The Operating System version may give an 52 | * indication about the compiler; Dhrystone itself performs no OS 53 | * calls in the measurement loop. 54 | * 55 | * The complete output generated by the program should be mailed 56 | * such that at least some checks for correctness can be made. 57 | * 58 | ************************************************************************* 59 | * 60 | * History: This version C/2.1 has been made for two reasons: 61 | * 62 | * 1) There is an obvious need for a common C version of 63 | * Dhrystone, since C is at present the most popular system 64 | * programming language for the class of processors 65 | * (microcomputers, minicomputers) where Dhrystone is used 66 | * most. There should be, as far as possible, only one C 67 | * version of Dhrystone such that results can be compared 68 | * without restrictions. In the past, the C versions 69 | * distributed by Rick Richardson (Version 1.1) and by 70 | * Reinhold Weicker had small (though not significant) 71 | * differences. 72 | * 73 | * 2) As far as it is possible without changes to the 74 | * Dhrystone statistics, optimizing compilers should be 75 | * prevented from removing significant statements. 76 | * 77 | * This C version has been developed in cooperation with 78 | * Rick Richardson (Tinton Falls, NJ), it incorporates many 79 | * ideas from the "Version 1.1" distributed previously by 80 | * him over the UNIX network Usenet. 81 | * I also thank Chaim Benedelac (National Semiconductor), 82 | * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), 83 | * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) 84 | * for their help with comments on earlier versions of the 85 | * benchmark. 86 | * 87 | * Changes: In the initialization part, this version follows mostly 88 | * Rick Richardson's version distributed via Usenet, not the 89 | * version distributed earlier via floppy disk by Reinhold 90 | * Weicker. As a concession to older compilers, names have 91 | * been made unique within the first 8 characters. Inside the 92 | * measurement loop, this version follows the version 93 | * previously distributed by Reinhold Weicker. 94 | * 95 | * At several places in the benchmark, code has been added, 96 | * but within the measurement loop only in branches that 97 | * are not executed. The intention is that optimizing 98 | * compilers should be prevented from moving code out of the 99 | * measurement loop, or from removing code altogether. Since 100 | * the statements that are executed within the measurement 101 | * loop have NOT been changed, the numbers defining the 102 | * "Dhrystone distribution" (distribution of statements, 103 | * operand types and locality) still hold. Except for 104 | * sophisticated optimizing compilers, execution times for 105 | * this version should be the same as for previous versions. 106 | * 107 | * Since it has proven difficult to subtract the time for the 108 | * measurement loop overhead in a correct way, the loop check 109 | * has been made a part of the benchmark. This does have 110 | * an impact - though a very minor one - on the distribution 111 | * statistics which have been updated for this version. 112 | * 113 | * All changes within the measurement loop are described 114 | * and discussed in the companion paper "Rationale for 115 | * Dhrystone version 2". 116 | * 117 | * Because of the self-imposed limitation that the order and 118 | * distribution of the executed statements should not be 119 | * changed, there are still cases where optimizing compilers 120 | * may not generate code for some statements. To a certain 121 | * degree, this is unavoidable for small synthetic 122 | * benchmarks. Users of the benchmark are advised to check 123 | * code listings whether code is generated for all statements 124 | * of Dhrystone. 125 | * 126 | * Version 2.1 is identical to version 2.0 distributed via 127 | * the UNIX network Usenet in March 1988 except that it 128 | * corrects some minor deficiencies that were found by users 129 | * of version 2.0. The only change within the measurement 130 | * loop is that a non-executed "else" part was added to the 131 | * "if" statement in Func_3, and a non-executed "else" part 132 | * removed from Proc_3. 133 | * 134 | ************************************************************************* 135 | * 136 | * Defines: The following "Defines" are possible: 137 | * -DROPT (default: Not defined) 138 | * As an approximation to what an average C 139 | * programmer might do, the "register" storage class 140 | * is applied (if enabled by -DROPT) 141 | * - for local variables, if they are used 142 | * (dynamically) five or more times 143 | * - for parameters if they are used (dynamically) 144 | * six or more times 145 | * Note that an optimal "register" strategy is 146 | * compiler-dependent, and that "register" 147 | * declarations do not necessarily lead to faster 148 | * execution. 149 | * -DNOSTRUCTASSIGN (default: Not defined) 150 | * Define if the C compiler does not support 151 | * assignment of structures. 152 | * -DNOENUMS (default: Not defined) 153 | * Define if the C compiler does not support 154 | * enumeration types. 155 | * 156 | ************************************************************************* 157 | * 158 | * Compilation model and measurement (IMPORTANT): 159 | * 160 | * This C version of Dhrystone consists of three files: 161 | * - dhry.h (this file, containing global definitions and comments) 162 | * - dhry_1.c (containing the code corresponding to Ada package Pack_1) 163 | * - dhry_2.c (containing the code corresponding to Ada package Pack_2) 164 | * 165 | * The following "ground rules" apply for measurements: 166 | * - Separate compilation 167 | * - No procedure merging 168 | * - Otherwise, compiler optimizations are allowed but should be 169 | * indicated 170 | * - Default results are those without register declarations 171 | * See the companion paper "Rationale for Dhrystone Version 2" for a more 172 | * detailed discussion of these ground rules. 173 | * 174 | * For 16-Bit processors (e.g. 80186, 80286), times for all compilation 175 | * models ("small", "medium", "large" etc.) should be given if possible, 176 | * together with a definition of these models for the compiler system 177 | * used. 178 | * 179 | ************************************************************************* 180 | * 181 | * Dhrystone (C version) statistics: 182 | * 183 | * [Comment from the first distribution, updated for version 2. 184 | * Note that because of language differences, the numbers are slightly 185 | * different from the Ada version.] 186 | * 187 | * The following program contains statements of a high level programming 188 | * language (here: C) in a distribution considered representative: 189 | * 190 | * assignments 52 (51.0 %) 191 | * control statements 33 (32.4 %) 192 | * procedure, function calls 17 (16.7 %) 193 | * 194 | * 103 statements are dynamically executed. The program is balanced with 195 | * respect to the three aspects: 196 | * 197 | * - statement type 198 | * - operand type 199 | * - operand locality 200 | * operand global, local, parameter, or constant. 201 | * 202 | * The combination of these three aspects is balanced only approximately. 203 | * 204 | * 1. Statement Type: 205 | * ----------------- number 206 | * 207 | * V1 = V2 9 208 | * (incl. V1 = F(..) 209 | * V = Constant 12 210 | * Assignment, 7 211 | * with array element 212 | * Assignment, 6 213 | * with record component 214 | * -- 215 | * 34 34 216 | * 217 | * X = Y +|-|"&&"|"|" Z 5 218 | * X = Y +|-|"==" Constant 6 219 | * X = X +|- 1 3 220 | * X = Y *|/ Z 2 221 | * X = Expression, 1 222 | * two operators 223 | * X = Expression, 1 224 | * three operators 225 | * -- 226 | * 18 18 227 | * 228 | * if .... 14 229 | * with "else" 7 230 | * without "else" 7 231 | * executed 3 232 | * not executed 4 233 | * for ... 7 | counted every time 234 | * while ... 4 | the loop condition 235 | * do ... while 1 | is evaluated 236 | * switch ... 1 237 | * break 1 238 | * declaration with 1 239 | * initialization 240 | * -- 241 | * 34 34 242 | * 243 | * P (...) procedure call 11 244 | * user procedure 10 245 | * library procedure 1 246 | * X = F (...) 247 | * function call 6 248 | * user function 5 249 | * library function 1 250 | * -- 251 | * 17 17 252 | * --- 253 | * 103 254 | * 255 | * The average number of parameters in procedure or function calls 256 | * is 1.82 (not counting the function values as implicit parameters). 257 | * 258 | * 259 | * 2. Operators 260 | * ------------ 261 | * number approximate 262 | * percentage 263 | * 264 | * Arithmetic 32 50.8 265 | * 266 | * + 21 33.3 267 | * - 7 11.1 268 | * * 3 4.8 269 | * / (int div) 1 1.6 270 | * 271 | * Comparison 27 42.8 272 | * 273 | * == 9 14.3 274 | * /= 4 6.3 275 | * > 1 1.6 276 | * < 3 4.8 277 | * >= 1 1.6 278 | * <= 9 14.3 279 | * 280 | * Logic 4 6.3 281 | * 282 | * && (AND-THEN) 1 1.6 283 | * | (OR) 1 1.6 284 | * ! (NOT) 2 3.2 285 | * 286 | * -- ----- 287 | * 63 100.1 288 | * 289 | * 290 | * 3. Operand Type (counted once per operand reference): 291 | * --------------- 292 | * number approximate 293 | * percentage 294 | * 295 | * Integer 175 72.3 % 296 | * Character 45 18.6 % 297 | * Pointer 12 5.0 % 298 | * String30 6 2.5 % 299 | * Array 2 0.8 % 300 | * Record 2 0.8 % 301 | * --- ------- 302 | * 242 100.0 % 303 | * 304 | * When there is an access path leading to the final operand (e.g. a 305 | * record component), only the final data type on the access path is 306 | * counted. 307 | * 308 | * 309 | * 4. Operand Locality: 310 | * ------------------- 311 | * number approximate 312 | * percentage 313 | * 314 | * local variable 114 47.1 % 315 | * global variable 22 9.1 % 316 | * parameter 45 18.6 % 317 | * value 23 9.5 % 318 | * reference 22 9.1 % 319 | * function result 6 2.5 % 320 | * constant 55 22.7 % 321 | * --- ------- 322 | * 242 100.0 % 323 | * 324 | * 325 | * The program does not compute anything meaningful, but it is 326 | * syntactically and semantically correct. All variables have a value 327 | * assigned to them before they are used as a source operand. 328 | * 329 | * There has been no explicit effort to account for the effects of a 330 | * cache, or to balance the use of long or short displacements for code 331 | * or data. 332 | * 333 | ************************************************************************* 334 | */ 335 | 336 | import core.stdc.stdio; 337 | import core.stdc.string; 338 | import core.stdc.stdlib; 339 | import std.string; 340 | 341 | /* Compiler and system dependent definitions: */ 342 | 343 | const double Mic_secs_Per_Second = 1000000.0; 344 | 345 | /* Berkeley UNIX C returns process times in seconds/HZ */ 346 | 347 | enum { Ident_1, Ident_2, Ident_3, Ident_4, Ident_5 } 348 | alias int Enumeration; 349 | 350 | /* for boolean and enumeration types in Ada, Pascal */ 351 | 352 | /* General definitions: */ 353 | 354 | const int StrLen = 30; 355 | 356 | alias int One_Thirty; 357 | alias int One_Fifty; 358 | alias char Capital_Letter; 359 | alias bool Boolean; 360 | alias char[StrLen] Str_30; 361 | alias int[50] Arr_1_Dim; 362 | alias int[50][50] Arr_2_Dim; 363 | 364 | struct record 365 | { 366 | record *Ptr_Comp; 367 | Enumeration Discr; 368 | union V 369 | { 370 | struct V1 371 | { 372 | Enumeration Enum_Comp; 373 | int Int_Comp; 374 | char[StrLen] Str_Comp; 375 | } 376 | V1 var_1; 377 | struct V2 378 | { 379 | Enumeration E_Comp_2; 380 | char[StrLen] Str_2_Comp; 381 | } 382 | V2 var_2; 383 | struct V3 384 | { 385 | char Ch_1_Comp; 386 | char Ch_2_Comp; 387 | } 388 | V3 var_3; 389 | } 390 | V variant; 391 | } 392 | 393 | alias record Rec_Type; 394 | alias record *Rec_Pointer; 395 | 396 | /* Global Variables: */ 397 | 398 | Rec_Pointer Ptr_Glob, 399 | Next_Ptr_Glob; 400 | int Int_Glob; 401 | Boolean Bool_Glob; 402 | char Ch_1_Glob, 403 | Ch_2_Glob; 404 | int[50] Arr_1_Glob; 405 | int[50][50] Arr_2_Glob; 406 | 407 | char[StrLen] Reg_Define = "Register option selected."; 408 | 409 | /* variables for time measurement: */ 410 | 411 | const int Too_Small_Time = 2; 412 | 413 | /* Measurements should last at least 2 seconds */ 414 | 415 | double Begin_Time, 416 | End_Time, 417 | User_Time; 418 | 419 | double Microseconds, 420 | Dhrystones_Per_Second, 421 | Vax_Mips; 422 | 423 | /* end of variables for time measurement */ 424 | void main() 425 | 426 | /*****/ 427 | 428 | /* main program, corresponds to procedures */ 429 | /* Main and Proc_0 in the Ada version */ 430 | { 431 | One_Fifty Int_1_Loc; 432 | One_Fifty Int_2_Loc; 433 | One_Fifty Int_3_Loc; 434 | char Ch_Index; 435 | Enumeration Enum_Loc; 436 | Str_30 Str_1_Loc; 437 | Str_30 Str_2_Loc; 438 | int Run_Index; 439 | int Number_Of_Runs; 440 | 441 | FILE *Ap; 442 | 443 | /* Initializations */ 444 | 445 | if ((Ap = fopen("dhry.res", "a+")) == null) 446 | { 447 | printf("Can not open dhry.res\n\n"); 448 | exit(1); 449 | } 450 | 451 | Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); 452 | Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof); 453 | 454 | Ptr_Glob.Ptr_Comp = Next_Ptr_Glob; 455 | Ptr_Glob.Discr = Ident_1; 456 | Ptr_Glob.variant.var_1.Enum_Comp = Ident_3; 457 | Ptr_Glob.variant.var_1.Int_Comp = 40; 458 | 459 | // strcpy (Ptr_Glob.variant.var_1.Str_Comp, 460 | // "DHRYSTONE PROGRAM, SOME STRING"); 461 | // strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); 462 | Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING"; 463 | Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING"; 464 | 465 | Arr_2_Glob [8][7] = 10; 466 | 467 | /* Was missing in published program. Without this statement, */ 468 | /* Arr_2_Glob [8][7] would have an undefined value. */ 469 | /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ 470 | /* overflow may occur for this array element. */ 471 | 472 | printf ("\n"); 473 | printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n"); 474 | printf ("\n"); 475 | printf ("Please give the number of runs through the benchmark: "); 476 | { 477 | int n; 478 | 479 | // scanf ("%d", &n); 480 | n = 10000000; 481 | Number_Of_Runs = n; 482 | } 483 | printf ("\n"); 484 | 485 | printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs); 486 | 487 | /***************/ 488 | /* Start timer */ 489 | /***************/ 490 | 491 | Begin_Time = dtime(); 492 | 493 | for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) 494 | { 495 | Proc_5(); 496 | Proc_4(); 497 | 498 | /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ 499 | Int_1_Loc = 2; 500 | Int_2_Loc = 3; 501 | 502 | // strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); 503 | Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING"; 504 | Enum_Loc = Ident_2; 505 | Bool_Glob = !Func_2 (Str_1_Loc, Str_2_Loc); 506 | 507 | /* Bool_Glob == 1 */ 508 | while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ 509 | { 510 | Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; 511 | 512 | /* Int_3_Loc == 7 */ 513 | Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); 514 | 515 | /* Int_3_Loc == 7 */ 516 | Int_1_Loc += 1; 517 | } /* while */ 518 | 519 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 520 | Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); 521 | 522 | /* Int_Glob == 5 */ 523 | Proc_1 (Ptr_Glob); 524 | 525 | for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) 526 | { 527 | /* loop body executed twice */ 528 | if (Enum_Loc == Func_1 (Ch_Index, 'C')) 529 | { 530 | /* then, not executed */ 531 | Proc_6 (Ident_1, &Enum_Loc); 532 | 533 | // strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); 534 | Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING"; 535 | Int_2_Loc = Run_Index; 536 | Int_Glob = Run_Index; 537 | } 538 | } 539 | 540 | /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ 541 | Int_2_Loc = Int_2_Loc * Int_1_Loc; 542 | Int_1_Loc = Int_2_Loc / Int_3_Loc; 543 | Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; 544 | 545 | /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ 546 | Proc_2 (&Int_1_Loc); 547 | 548 | /* Int_1_Loc == 5 */ 549 | } /* loop "for Run_Index" */ 550 | 551 | /**************/ 552 | /* Stop timer */ 553 | /**************/ 554 | 555 | End_Time = dtime(); 556 | 557 | printf ("Execution ends\n"); 558 | printf ("\n"); 559 | printf ("Final values of the variables used in the benchmark:\n"); 560 | printf ("\n"); 561 | printf ("Int_Glob: %d\n", Int_Glob); 562 | printf (" should be: %d\n", 5); 563 | printf ("Bool_Glob: %d\n", Bool_Glob); 564 | printf (" should be: %d\n", 1); 565 | printf ("Ch_1_Glob: %c\n", Ch_1_Glob); 566 | printf (" should be: %c\n", cast(int) 'A'); 567 | printf ("Ch_2_Glob: %c\n", Ch_2_Glob); 568 | printf (" should be: %c\n", cast(int) 'B'); 569 | printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); 570 | printf (" should be: %d\n", 7); 571 | printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); 572 | printf (" should be: Number_Of_Runs + 10\n"); 573 | printf ("Ptr_Glob.\n"); 574 | printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp); 575 | printf (" should be: (implementation-dependent)\n"); 576 | printf (" Discr: %d\n", Ptr_Glob.Discr); 577 | printf (" should be: %d\n", 0); 578 | printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp); 579 | printf (" should be: %d\n", 2); 580 | printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp); 581 | printf (" should be: %d\n", 17); 582 | printf (" Str_Comp: %.*s\n", cast(int) Ptr_Glob.variant.var_1.Str_Comp.length, 583 | Ptr_Glob.variant.var_1.Str_Comp.ptr); 584 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 585 | printf ("Next_Ptr_Glob.\n"); 586 | printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp); 587 | printf (" should be: (implementation-dependent), same as above\n"); 588 | printf (" Discr: %d\n", Next_Ptr_Glob.Discr); 589 | printf (" should be: %d\n", 0); 590 | printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp); 591 | printf (" should be: %d\n", 1); 592 | printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp); 593 | printf (" should be: %d\n", 18); 594 | printf (" Str_Comp: %.*s\n", cast(int) Next_Ptr_Glob.variant.var_1.Str_Comp.length, 595 | Next_Ptr_Glob.variant.var_1.Str_Comp.ptr); 596 | printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); 597 | printf ("Int_1_Loc: %d\n", Int_1_Loc); 598 | printf (" should be: %d\n", 5); 599 | printf ("Int_2_Loc: %d\n", Int_2_Loc); 600 | printf (" should be: %d\n", 13); 601 | printf ("Int_3_Loc: %d\n", Int_3_Loc); 602 | printf (" should be: %d\n", 7); 603 | printf ("Enum_Loc: %d\n", Enum_Loc); 604 | printf (" should be: %d\n", 1); 605 | printf ("Str_1_Loc: %.*s\n", cast(int) Str_1_Loc.length, Str_1_Loc.ptr); 606 | printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); 607 | printf ("Str_2_Loc: %.*s\n", cast(int) Str_2_Loc.length, Str_2_Loc.ptr); 608 | printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); 609 | printf ("\n"); 610 | 611 | User_Time = End_Time - Begin_Time; 612 | 613 | if (User_Time < Too_Small_Time) 614 | { 615 | printf ("Measured time too small to obtain meaningful results\n"); 616 | printf ("Please increase number of runs\n"); 617 | printf ("\n"); 618 | } 619 | else 620 | { 621 | Microseconds = User_Time * Mic_secs_Per_Second 622 | / cast(double) Number_Of_Runs; 623 | Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time; 624 | Vax_Mips = Dhrystones_Per_Second / 1757.0; 625 | 626 | printf ("Register option selected? NO\n"); 627 | strcpy(Reg_Define.ptr, "Register option not selected."); 628 | printf ("Microseconds for one run through Dhrystone: "); 629 | printf ("%7.1lf \n", Microseconds); 630 | printf ("Dhrystones per Second: "); 631 | printf ("%10.1lf \n", Dhrystones_Per_Second); 632 | printf ("VAX MIPS rating = %10.3lf \n", Vax_Mips); 633 | printf ("\n"); 634 | 635 | fprintf(Ap, "\n"); 636 | fprintf(Ap, "Dhrystone Benchmark, Version 2.1 (Language: D)\n"); 637 | fprintf(Ap, "%*s\n", Reg_Define.ptr); 638 | fprintf(Ap, "Microseconds for one loop: %7.1lf\n", Microseconds); 639 | fprintf(Ap, "Dhrystones per second: %10.1lf\n", Dhrystones_Per_Second); 640 | fprintf(Ap, "VAX MIPS rating: %10.3lf\n", Vax_Mips); 641 | fclose(Ap); 642 | } 643 | } 644 | 645 | void Proc_1(Rec_Pointer Ptr_Val_Par) 646 | 647 | /******************/ 648 | 649 | /* executed once */ 650 | { 651 | Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp; 652 | 653 | /* == Ptr_Glob_Next */ 654 | /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */ 655 | /* corresponds to "rename" in Ada, "with" in Pascal */ 656 | 657 | *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob; 658 | Ptr_Val_Par.variant.var_1.Int_Comp = 5; 659 | Next_Record.variant.var_1.Int_Comp 660 | = Ptr_Val_Par.variant.var_1.Int_Comp; 661 | Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp; 662 | Proc_3 (&Next_Record.Ptr_Comp); 663 | 664 | /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp 665 | == Ptr_Glob.Ptr_Comp */ 666 | if (Next_Record.Discr == Ident_1) 667 | { 668 | /* then, executed */ 669 | Next_Record.variant.var_1.Int_Comp = 6; 670 | Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp, 671 | &Next_Record.variant.var_1.Enum_Comp); 672 | Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp; 673 | Proc_7 (Next_Record.variant.var_1.Int_Comp, 10, 674 | &Next_Record.variant.var_1.Int_Comp); 675 | } 676 | else /* not executed */ 677 | *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp; 678 | } /* Proc_1 */ 679 | void Proc_2(One_Fifty *Int_Par_Ref) 680 | 681 | /******************/ 682 | /* executed once */ 683 | /* *Int_Par_Ref == 1, becomes 4 */ 684 | { 685 | One_Fifty Int_Loc; 686 | Enumeration Enum_Loc; 687 | 688 | Int_Loc = *Int_Par_Ref + 10; 689 | 690 | do /* executed once */ 691 | if (Ch_1_Glob == 'A') 692 | { 693 | /* then, executed */ 694 | Int_Loc -= 1; 695 | *Int_Par_Ref = Int_Loc - Int_Glob; 696 | Enum_Loc = Ident_1; 697 | } 698 | 699 | /* if */ 700 | while (Enum_Loc != Ident_1); /* true */ 701 | } /* Proc_2 */ 702 | void Proc_3(Rec_Pointer *Ptr_Ref_Par) 703 | 704 | /******************/ 705 | /* executed once */ 706 | /* Ptr_Ref_Par becomes Ptr_Glob */ 707 | { 708 | if (Ptr_Glob != null) 709 | /* then, executed */ 710 | *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp; 711 | 712 | Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp); 713 | } /* Proc_3 */ 714 | void Proc_4() /* without parameters */ 715 | /*******/ 716 | /* executed once */ 717 | { 718 | Boolean Bool_Loc; 719 | 720 | Bool_Loc = Ch_1_Glob == 'A'; 721 | Bool_Glob = Bool_Loc | Bool_Glob; 722 | Ch_2_Glob = 'B'; 723 | } /* Proc_4 */ 724 | void Proc_5() /* without parameters */ 725 | /*******/ 726 | /* executed once */ 727 | { 728 | Ch_1_Glob = 'A'; 729 | Bool_Glob = false; 730 | } /* Proc_5 */ 731 | void Proc_6(Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par) 732 | 733 | /*********************************/ 734 | /* executed once */ 735 | /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ 736 | { 737 | *Enum_Ref_Par = Enum_Val_Par; 738 | 739 | if (!Func_3 (Enum_Val_Par)) 740 | /* then, not executed */ 741 | *Enum_Ref_Par = Ident_4; 742 | 743 | switch (Enum_Val_Par) 744 | { 745 | case Ident_1: 746 | *Enum_Ref_Par = Ident_1; 747 | break; 748 | 749 | case Ident_2: 750 | 751 | if (Int_Glob > 100) 752 | /* then */ 753 | *Enum_Ref_Par = Ident_1; 754 | else *Enum_Ref_Par = Ident_4; 755 | 756 | break; 757 | 758 | case Ident_3: /* executed */ 759 | *Enum_Ref_Par = Ident_2; 760 | break; 761 | 762 | case Ident_4: 763 | break; 764 | 765 | case Ident_5: 766 | *Enum_Ref_Par = Ident_3; 767 | break; 768 | 769 | default: 770 | } /* switch */ 771 | 772 | } /* Proc_6 */ 773 | void Proc_7(One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref) 774 | 775 | /**********************************************/ 776 | /* executed three times */ 777 | /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ 778 | /* Int_Par_Ref becomes 7 */ 779 | /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ 780 | /* Int_Par_Ref becomes 17 */ 781 | /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ 782 | /* Int_Par_Ref becomes 18 */ 783 | { 784 | One_Fifty Int_Loc; 785 | 786 | Int_Loc = Int_1_Par_Val + 2; 787 | *Int_Par_Ref = Int_2_Par_Val + Int_Loc; 788 | } /* Proc_7 */ 789 | void Proc_8(ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val) 790 | 791 | /*********************************************************************/ 792 | /* executed once */ 793 | /* Int_Par_Val_1 == 3 */ 794 | /* Int_Par_Val_2 == 7 */ 795 | { 796 | One_Fifty Int_Index; 797 | One_Fifty Int_Loc; 798 | 799 | Int_Loc = Int_1_Par_Val + 5; 800 | Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; 801 | Arr_1_Par_Ref [Int_Loc + 1] = Arr_1_Par_Ref [Int_Loc]; 802 | Arr_1_Par_Ref [Int_Loc + 30] = Int_Loc; 803 | 804 | for (Int_Index = Int_Loc; Int_Index <= Int_Loc + 1; ++Int_Index) 805 | Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; 806 | 807 | Arr_2_Par_Ref [Int_Loc] [Int_Loc - 1] += 1; 808 | Arr_2_Par_Ref [Int_Loc + 20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; 809 | Int_Glob = 5; 810 | } /* Proc_8 */ 811 | Enumeration Func_1(Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val) 812 | 813 | /*************************************************/ 814 | /* executed three times */ 815 | /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ 816 | /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ 817 | /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ 818 | { 819 | Capital_Letter Ch_1_Loc; 820 | Capital_Letter Ch_2_Loc; 821 | 822 | Ch_1_Loc = Ch_1_Par_Val; 823 | Ch_2_Loc = Ch_1_Loc; 824 | 825 | if (Ch_2_Loc != Ch_2_Par_Val) 826 | /* then, executed */ 827 | return (Ident_1); 828 | else /* not executed */ 829 | { 830 | Ch_1_Glob = Ch_1_Loc; 831 | return (Ident_2); 832 | } 833 | } /* Func_1 */ 834 | Boolean Func_2(Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref) 835 | 836 | /*************************************************/ 837 | /* executed once */ 838 | /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ 839 | /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ 840 | { 841 | One_Thirty Int_Loc; 842 | Capital_Letter Ch_Loc; 843 | 844 | Int_Loc = 2; 845 | 846 | while (Int_Loc <= 2) /* loop body executed once */ 847 | if (Func_1 (Str_1_Par_Ref[Int_Loc], 848 | Str_2_Par_Ref[Int_Loc + 1]) == Ident_1) 849 | { 850 | /* then, executed */ 851 | Ch_Loc = 'A'; 852 | Int_Loc += 1; 853 | } 854 | 855 | /* if, while */ 856 | 857 | if (Ch_Loc >= 'W' && Ch_Loc < 'Z') 858 | /* then, not executed */ 859 | Int_Loc = 7; 860 | 861 | if (Ch_Loc == 'R') 862 | /* then, not executed */ 863 | return (true); 864 | else /* executed */ 865 | { 866 | // if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) 867 | // if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0) 868 | if (Str_1_Par_Ref > Str_2_Par_Ref) 869 | { 870 | /* then, not executed */ 871 | Int_Loc += 7; 872 | Int_Glob = Int_Loc; 873 | return (true); 874 | } 875 | else /* executed */ 876 | return (false); 877 | } /* if Ch_Loc */ 878 | 879 | } /* Func_2 */ 880 | Boolean Func_3(Enumeration Enum_Par_Val) 881 | 882 | /***************************/ 883 | /* executed once */ 884 | /* Enum_Par_Val == Ident_3 */ 885 | { 886 | Enumeration Enum_Loc; 887 | 888 | Enum_Loc = Enum_Par_Val; 889 | 890 | if (Enum_Loc == Ident_3) 891 | /* then, executed */ 892 | return (true); 893 | else /* not executed */ 894 | return (false); 895 | } /* Func_3 */ 896 | 897 | version (Windows) 898 | { 899 | import core.sys.windows.winbase; 900 | 901 | double dtime() 902 | { 903 | double q; 904 | 905 | q = cast(double) GetTickCount() * 1.0e-03; 906 | 907 | return q; 908 | } 909 | } 910 | 911 | version (linux) 912 | { 913 | import core.stdc.time; 914 | 915 | double dtime() 916 | { 917 | double q; 918 | 919 | q = cast(double) time(null); 920 | 921 | return q; 922 | } 923 | } 924 | 925 | version (OSX) // supplied by Anders F Bjorklund 926 | { 927 | import core.sys.posix.sys.time; 928 | 929 | double dtime() 930 | { 931 | double q; 932 | timeval tv; 933 | 934 | gettimeofday(&tv, null); 935 | q = cast(double) tv.tv_sec + cast(double) tv.tv_usec * 1.0e-6; 936 | 937 | return q; 938 | } 939 | } 940 | -------------------------------------------------------------------------------- /dmdsamples/dserver.d: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Hello Object DLL Self-Registering Server 4 | * Heavily modified from: 5 | */ 6 | /* 7 | * SELFREG.CPP 8 | * Server Self-Registrtation Utility, Chapter 5 9 | * 10 | * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved 11 | * 12 | * Kraig Brockschmidt, Microsoft 13 | * Internet : kraigb@microsoft.com 14 | * Compuserve: >INTERNET:kraigb@microsoft.com 15 | */ 16 | 17 | import core.stdc.stdio; 18 | import core.stdc.stdlib; 19 | import core.stdc.string; 20 | import std.string; 21 | import core.sys.windows.com; 22 | import core.sys.windows.winbase; 23 | import core.sys.windows.windef; 24 | import core.sys.windows.winreg; 25 | 26 | import chello; 27 | 28 | // This class factory object creates Hello objects. 29 | 30 | class CHelloClassFactory : ComObject, IClassFactory 31 | { 32 | public: 33 | this() 34 | { 35 | printf("CHelloClassFactory()\n"); 36 | } 37 | 38 | ~this() 39 | { 40 | printf("~CHelloClassFactory()"); 41 | } 42 | 43 | extern (Windows) : 44 | 45 | // IUnknown members 46 | override HRESULT QueryInterface(const (IID)*riid, LPVOID *ppv) 47 | { 48 | printf("CHelloClassFactory.QueryInterface()\n"); 49 | 50 | if (IID_IUnknown == *riid) 51 | { 52 | printf("IUnknown\n"); 53 | *ppv = cast(void*) cast(IUnknown) this; 54 | } 55 | else if (IID_IClassFactory == *riid) 56 | { 57 | printf("IClassFactory\n"); 58 | *ppv = cast(void*) cast(IClassFactory) this; 59 | } 60 | else 61 | { 62 | *ppv = null; 63 | return E_NOINTERFACE; 64 | } 65 | 66 | AddRef(); 67 | return NOERROR; 68 | } 69 | 70 | // IClassFactory members 71 | override HRESULT CreateInstance(IUnknown pUnkOuter, IID*riid, LPVOID *ppvObj) 72 | { 73 | CHello pObj; 74 | HRESULT hr; 75 | 76 | printf("CHelloClassFactory.CreateInstance()\n"); 77 | *ppvObj = null; 78 | hr = E_OUTOFMEMORY; 79 | 80 | // Verify that a controlling unknown asks for IUnknown 81 | if (null !is pUnkOuter && memcmp(&IID_IUnknown, riid, IID.sizeof)) 82 | return CLASS_E_NOAGGREGATION; 83 | 84 | // Create the object passing function to notify on destruction. 85 | pObj = new CHello(pUnkOuter, &ObjectDestroyed); 86 | 87 | if (!pObj) 88 | return hr; 89 | 90 | if (pObj.Init()) 91 | { 92 | hr = pObj.QueryInterface(riid, ppvObj); 93 | } 94 | 95 | // Kill the object if initial creation or Init failed. 96 | if (FAILED(hr)) 97 | delete pObj; 98 | else 99 | g_cObj++; 100 | 101 | return hr; 102 | } 103 | 104 | HRESULT LockServer(BOOL fLock) 105 | { 106 | printf("CHelloClassFactory.LockServer(%d)\n", fLock); 107 | 108 | if (fLock) 109 | g_cLock++; 110 | else 111 | g_cLock--; 112 | 113 | return NOERROR; 114 | } 115 | }; 116 | 117 | // Count number of objects and number of locks. 118 | ULONG g_cObj =0; 119 | ULONG g_cLock=0; 120 | 121 | import core.sys.windows.dll; 122 | HINSTANCE g_hInst; 123 | 124 | extern (Windows): 125 | 126 | BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) 127 | { 128 | switch (ulReason) 129 | { 130 | case DLL_PROCESS_ATTACH: 131 | g_hInst = hInstance; 132 | dll_process_attach( hInstance, true ); 133 | printf("ATTACH\n"); 134 | break; 135 | 136 | case DLL_PROCESS_DETACH: 137 | printf("DETACH\n"); 138 | dll_process_detach( hInstance, true ); 139 | break; 140 | 141 | case DLL_THREAD_ATTACH: 142 | dll_thread_attach( true, true ); 143 | printf("THREAD_ATTACH\n"); 144 | break; 145 | 146 | case DLL_THREAD_DETACH: 147 | dll_thread_detach( true, true ); 148 | printf("THREAD_DETACH\n"); 149 | break; 150 | 151 | default: 152 | assert(0); 153 | } 154 | return true; 155 | } 156 | 157 | /* 158 | * DllGetClassObject 159 | * 160 | * Purpose: 161 | * Provides an IClassFactory for a given CLSID that this DLL is 162 | * registered to support. This DLL is placed under the CLSID 163 | * in the registration database as the InProcServer. 164 | * 165 | * Parameters: 166 | * clsID REFCLSID that identifies the class factory 167 | * desired. Since this parameter is passed this 168 | * DLL can handle any number of objects simply 169 | * by returning different class factories here 170 | * for different CLSIDs. 171 | * 172 | * riid REFIID specifying the interface the caller wants 173 | * on the class object, usually IID_ClassFactory. 174 | * 175 | * ppv LPVOID * in which to return the interface 176 | * pointer. 177 | * 178 | * Return Value: 179 | * HRESULT NOERROR on success, otherwise an error code. 180 | */ 181 | HRESULT DllGetClassObject(CLSID*rclsid, IID*riid, LPVOID *ppv) 182 | { 183 | HRESULT hr; 184 | CHelloClassFactory pObj; 185 | 186 | printf("DllGetClassObject()\n"); 187 | 188 | if (CLSID_Hello != *rclsid) 189 | return E_FAIL; 190 | 191 | pObj = new CHelloClassFactory(); 192 | 193 | if (!pObj) 194 | return E_OUTOFMEMORY; 195 | 196 | hr = pObj.QueryInterface(riid, ppv); 197 | 198 | if (FAILED(hr)) 199 | delete pObj; 200 | 201 | return hr; 202 | } 203 | 204 | /* 205 | * Answers if the DLL can be freed, that is, if there are no 206 | * references to anything this DLL provides. 207 | * 208 | * Return Value: 209 | * BOOL true if nothing is using us, false otherwise. 210 | */ 211 | HRESULT DllCanUnloadNow() 212 | { 213 | SCODE sc; 214 | 215 | printf("DllCanUnloadNow()\n"); 216 | 217 | // Any locks or objects? 218 | sc = (0 == g_cObj && 0 == g_cLock) ? S_OK : S_FALSE; 219 | return sc; 220 | } 221 | 222 | /* 223 | * Instructs the server to create its own registry entries 224 | * 225 | * Return Value: 226 | * HRESULT NOERROR if registration successful, error 227 | * otherwise. 228 | */ 229 | HRESULT DllRegisterServer() 230 | { 231 | char[128] szID; 232 | char[128] szCLSID; 233 | char[512] szModule; 234 | 235 | printf("DllRegisterServer()\n"); 236 | 237 | // Create some base key strings. 238 | StringFromGUID2(&CLSID_Hello, cast(LPOLESTR) szID, 128); 239 | unicode2ansi(szID.ptr); 240 | strcpy(szCLSID.ptr, "CLSID\\"); 241 | strcat(szCLSID.ptr, szID.ptr); 242 | 243 | // Create ProgID keys 244 | SetKeyAndValue("Hello1.0", null, "Hello Object"); 245 | SetKeyAndValue("Hello1.0", "CLSID", szID.ptr); 246 | 247 | // Create VersionIndependentProgID keys 248 | SetKeyAndValue("Hello", null, "Hello Object"); 249 | SetKeyAndValue("Hello", "CurVer", "Hello1.0"); 250 | SetKeyAndValue("Hello", "CLSID", szID.ptr); 251 | 252 | // Create entries under CLSID 253 | SetKeyAndValue(szCLSID.ptr, null, "Hello Object"); 254 | SetKeyAndValue(szCLSID.ptr, "ProgID", "Hello1.0"); 255 | SetKeyAndValue(szCLSID.ptr, "VersionIndependentProgID", "Hello"); 256 | SetKeyAndValue(szCLSID.ptr, "NotInsertable", null); 257 | 258 | GetModuleFileNameA(g_hInst, szModule.ptr, szModule.length); 259 | 260 | SetKeyAndValue(szCLSID.ptr, "InprocServer32", szModule.ptr); 261 | return NOERROR; 262 | } 263 | 264 | /* 265 | * Purpose: 266 | * Instructs the server to remove its own registry entries 267 | * 268 | * Return Value: 269 | * HRESULT NOERROR if registration successful, error 270 | * otherwise. 271 | */ 272 | HRESULT DllUnregisterServer() 273 | { 274 | char[128] szID; 275 | char[128] szCLSID; 276 | char[256] szTemp; 277 | 278 | printf("DllUnregisterServer()\n"); 279 | 280 | // Create some base key strings. 281 | StringFromGUID2(&CLSID_Hello, cast(LPOLESTR) szID, 128); 282 | unicode2ansi(szID.ptr); 283 | strcpy(szCLSID.ptr, "CLSID\\"); 284 | strcat(szCLSID.ptr, szID.ptr); 285 | 286 | RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello\\CurVer"); 287 | RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello\\CLSID"); 288 | RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello"); 289 | 290 | RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello1.0\\CLSID"); 291 | RegDeleteKeyA(HKEY_CLASSES_ROOT, "Hello1.0"); 292 | 293 | strcpy(szTemp.ptr, szCLSID.ptr); 294 | strcat(szTemp.ptr, "\\"); 295 | strcat(szTemp.ptr, "ProgID"); 296 | RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); 297 | 298 | strcpy(szTemp.ptr, szCLSID.ptr); 299 | strcat(szTemp.ptr, "\\"); 300 | strcat(szTemp.ptr, "VersionIndependentProgID"); 301 | RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); 302 | 303 | strcpy(szTemp.ptr, szCLSID.ptr); 304 | strcat(szTemp.ptr, "\\"); 305 | strcat(szTemp.ptr, "NotInsertable"); 306 | RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); 307 | 308 | strcpy(szTemp.ptr, szCLSID.ptr); 309 | strcat(szTemp.ptr, "\\"); 310 | strcat(szTemp.ptr, "InprocServer32"); 311 | RegDeleteKeyA(HKEY_CLASSES_ROOT, szTemp.ptr); 312 | 313 | RegDeleteKeyA(HKEY_CLASSES_ROOT, szCLSID.ptr); 314 | return NOERROR; 315 | } 316 | 317 | /* 318 | * SetKeyAndValue 319 | * 320 | * Purpose: 321 | * Private helper function for DllRegisterServer that creates 322 | * a key, sets a value, and closes that key. 323 | * 324 | * Parameters: 325 | * pszKey LPTSTR to the name of the key 326 | * pszSubkey LPTSTR ro the name of a subkey 327 | * pszValue LPTSTR to the value to store 328 | * 329 | * Return Value: 330 | * BOOL true if successful, false otherwise. 331 | */ 332 | BOOL SetKeyAndValue(LPCSTR pszKey, LPCSTR pszSubkey, LPCSTR pszValue) 333 | { 334 | HKEY hKey; 335 | char[256] szKey; 336 | BOOL result; 337 | 338 | strcpy(szKey.ptr, pszKey); 339 | 340 | if (pszSubkey) 341 | { 342 | strcat(szKey.ptr, "\\"); 343 | strcat(szKey.ptr, pszSubkey); 344 | } 345 | 346 | result = true; 347 | 348 | int regresult = RegCreateKeyExA(HKEY_CLASSES_ROOT, 349 | szKey.ptr, 0, null, REG_OPTION_NON_VOLATILE, 350 | KEY_ALL_ACCESS, null, &hKey, null); 351 | if (ERROR_SUCCESS != regresult) 352 | { 353 | result = false; 354 | // If the value is 5, you'll need to run the program with Administrator privileges 355 | printf("RegCreateKeyExA() failed with 0x%x\n", regresult); 356 | } 357 | else 358 | { 359 | if (null != pszValue) 360 | { 361 | if (RegSetValueExA(hKey, null, 0, REG_SZ, cast(BYTE *) pszValue, 362 | cast(int)((strlen(pszValue) + 1) * char.sizeof)) != ERROR_SUCCESS) 363 | result = false; 364 | } 365 | 366 | if (RegCloseKey(hKey) != ERROR_SUCCESS) 367 | result = false; 368 | } 369 | 370 | if (!result) 371 | printf("SetKeyAndValue() failed\n"); 372 | 373 | return result; 374 | } 375 | 376 | /* 377 | * ObjectDestroyed 378 | * 379 | * Purpose: 380 | * Function for the Hello object to call when it gets destroyed. 381 | * Since we're in a DLL we only track the number of objects here, 382 | * letting DllCanUnloadNow take care of the rest. 383 | */ 384 | 385 | extern (D) void ObjectDestroyed() 386 | { 387 | printf("ObjectDestroyed()\n"); 388 | g_cObj--; 389 | } 390 | 391 | void unicode2ansi(char *s) 392 | { 393 | wchar *w; 394 | 395 | for (w = cast(wchar *) s; *w; w++) 396 | *s++ = cast(char)*w; 397 | 398 | *s = 0; 399 | } 400 | -------------------------------------------------------------------------------- /dmdsamples/dserver64.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | DllGetClassObject 3 | DllCanUnloadNow 4 | DllRegisterServer 5 | DllUnregisterServer 6 | -------------------------------------------------------------------------------- /dmdsamples/hello.d: -------------------------------------------------------------------------------- 1 | 2 | import std.stdio; 3 | 4 | void main(string[] args) 5 | { 6 | writeln("hello world"); 7 | writefln("args.length = %d", args.length); 8 | 9 | foreach (index, arg; args) 10 | { 11 | writefln("args[%d] = '%s'", index, arg); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dmdsamples/htmlget.d: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | HTMLget written by Christopher E. Miller 4 | This code is public domain. 5 | You may use it for any purpose. 6 | This code has no warranties and is provided 'as-is'. 7 | */ 8 | 9 | debug = HTMLGET; 10 | 11 | import std.string, std.conv, std.stdio; 12 | import std.socket; 13 | 14 | int main(string[] args) 15 | { 16 | if (args.length < 2) 17 | { 18 | writeln("Usage:"); 19 | writeln(" htmlget "); 20 | return 0; 21 | } 22 | 23 | string url = args[1]; 24 | auto i = indexOf(url, "://"); 25 | 26 | if (i != -1) 27 | { 28 | if (icmp(url[0 .. i], "http")) 29 | throw new Exception("http:// expected"); 30 | url = url[i + 3 .. $]; 31 | } 32 | 33 | i = indexOf(url, '#'); 34 | 35 | if (i != -1) // Remove anchor ref. 36 | url = url[0 .. i]; 37 | 38 | i = indexOf(url, '/'); 39 | string domain; 40 | 41 | if (i == -1) 42 | { 43 | domain = url; 44 | url = "/"; 45 | } 46 | else 47 | { 48 | domain = url[0 .. i]; 49 | url = url[i .. $]; 50 | } 51 | 52 | ushort port; 53 | i = indexOf(domain, ':'); 54 | 55 | if (i == -1) 56 | { 57 | port = 80; // Default HTTP port. 58 | } 59 | else 60 | { 61 | port = to!ushort(domain[i + 1 .. $]); 62 | domain = domain[0 .. i]; 63 | } 64 | 65 | debug (HTMLGET) 66 | writefln("Connecting to %s on port %d...", domain, port); 67 | 68 | Socket sock = new TcpSocket(new InternetAddress(domain, port)); 69 | scope(exit) sock.close(); 70 | 71 | debug (HTMLGET) 72 | writefln("Connected! Requesting URL \"%s\"...", url); 73 | 74 | if (port != 80) 75 | domain = domain ~ ":" ~ to!string(port); 76 | 77 | sock.send("GET " ~ url ~ " HTTP/1.0\r\n" ~ 78 | "Host: " ~ domain ~ "\r\n" ~ 79 | "\r\n"); 80 | 81 | // Skip HTTP header. 82 | while (true) 83 | { 84 | char[] line; 85 | char[1] buf; 86 | while(sock.receive(buf)) 87 | { 88 | line ~= buf; 89 | if (buf[0] == '\n') 90 | break; 91 | } 92 | 93 | if (!line.length) 94 | break; 95 | 96 | write(line); 97 | 98 | enum CONTENT_TYPE_NAME = "Content-Type: "; 99 | 100 | if (line.length > CONTENT_TYPE_NAME.length && 101 | !icmp(CONTENT_TYPE_NAME, line[0 .. CONTENT_TYPE_NAME.length])) 102 | { 103 | auto type = line[CONTENT_TYPE_NAME.length .. $]; 104 | 105 | if (type.length <= 5 || icmp("text/", type[0 .. 5])) 106 | throw new Exception("URL is not text"); 107 | } 108 | } 109 | 110 | return 0; 111 | } 112 | -------------------------------------------------------------------------------- /dmdsamples/listener.d: -------------------------------------------------------------------------------- 1 | /* 2 | D listener written by Christopher E. Miller 3 | Modified by Orvid King 4 | This code is public domain. 5 | You may use it for any purpose. 6 | This code has no warranties and is provided 'as-is'. 7 | */ 8 | 9 | import std.algorithm : remove; 10 | import std.conv : to; 11 | import std.socket : InternetAddress, Socket, SocketException, SocketSet, TcpSocket; 12 | import std.stdio : writeln, writefln; 13 | 14 | void main(string[] args) 15 | { 16 | ushort port; 17 | 18 | if (args.length >= 2) 19 | port = to!ushort(args[1]); 20 | else 21 | port = 4444; 22 | 23 | auto listener = new TcpSocket(); 24 | assert(listener.isAlive); 25 | listener.blocking = false; 26 | listener.bind(new InternetAddress(port)); 27 | listener.listen(10); 28 | writefln("Listening on port %d.", port); 29 | 30 | enum MAX_CONNECTIONS = 60; 31 | // Room for listener. 32 | auto socketSet = new SocketSet(MAX_CONNECTIONS + 1); 33 | Socket[] reads; 34 | 35 | while (true) 36 | { 37 | socketSet.add(listener); 38 | 39 | foreach (sock; reads) 40 | socketSet.add(sock); 41 | 42 | Socket.select(socketSet, null, null); 43 | 44 | for (size_t i = 0; i < reads.length; i++) 45 | { 46 | if (socketSet.isSet(reads[i])) 47 | { 48 | char[1024] buf; 49 | auto datLength = reads[i].receive(buf[]); 50 | 51 | if (datLength == Socket.ERROR) 52 | writeln("Connection error."); 53 | else if (datLength != 0) 54 | { 55 | writefln("Received %d bytes from %s: \"%s\"", datLength, reads[i].remoteAddress().toString(), buf[0..datLength]); 56 | continue; 57 | } 58 | else 59 | { 60 | try 61 | { 62 | // if the connection closed due to an error, remoteAddress() could fail 63 | writefln("Connection from %s closed.", reads[i].remoteAddress().toString()); 64 | } 65 | catch (SocketException) 66 | { 67 | writeln("Connection closed."); 68 | } 69 | } 70 | 71 | // release socket resources now 72 | reads[i].close(); 73 | 74 | reads = reads.remove(i); 75 | // i will be incremented by the for, we don't want it to be. 76 | i--; 77 | 78 | writefln("\tTotal connections: %d", reads.length); 79 | } 80 | } 81 | 82 | if (socketSet.isSet(listener)) // connection request 83 | { 84 | Socket sn = null; 85 | scope (failure) 86 | { 87 | writefln("Error accepting"); 88 | 89 | if (sn) 90 | sn.close(); 91 | } 92 | sn = listener.accept(); 93 | assert(sn.isAlive); 94 | assert(listener.isAlive); 95 | 96 | if (reads.length < MAX_CONNECTIONS) 97 | { 98 | writefln("Connection from %s established.", sn.remoteAddress().toString()); 99 | reads ~= sn; 100 | writefln("\tTotal connections: %d", reads.length); 101 | } 102 | else 103 | { 104 | writefln("Rejected connection from %s; too many connections.", sn.remoteAddress().toString()); 105 | sn.close(); 106 | assert(!sn.isAlive); 107 | assert(listener.isAlive); 108 | } 109 | } 110 | 111 | socketSet.reset(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /dmdsamples/mydll/build.bat: -------------------------------------------------------------------------------- 1 | ..\..\..\windows\bin\dmd -ofmydll.dll -L/IMPLIB mydll.d dll.d mydll.def 2 | ..\..\..\windows\bin\dmd test.d mydll.lib 3 | -------------------------------------------------------------------------------- /dmdsamples/mydll/dll.d: -------------------------------------------------------------------------------- 1 | 2 | // Public Domain 3 | 4 | import core.sys.windows.windef; 5 | import core.sys.windows.dll; 6 | 7 | __gshared HINSTANCE g_hInst; 8 | 9 | extern (Windows) 10 | BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) 11 | { 12 | switch (ulReason) 13 | { 14 | case DLL_PROCESS_ATTACH: 15 | g_hInst = hInstance; 16 | dll_process_attach( hInstance, true ); 17 | break; 18 | 19 | case DLL_PROCESS_DETACH: 20 | dll_process_detach( hInstance, true ); 21 | break; 22 | 23 | case DLL_THREAD_ATTACH: 24 | dll_thread_attach( true, true ); 25 | break; 26 | 27 | case DLL_THREAD_DETACH: 28 | dll_thread_detach( true, true ); 29 | break; 30 | 31 | default: 32 | assert(0); 33 | } 34 | 35 | return true; 36 | } 37 | -------------------------------------------------------------------------------- /dmdsamples/mydll/mydll.d: -------------------------------------------------------------------------------- 1 | 2 | module mydll; 3 | import core.stdc.stdio; 4 | 5 | export void dllprint() { printf("hello dll world\n"); } 6 | -------------------------------------------------------------------------------- /dmdsamples/mydll/mydll.def: -------------------------------------------------------------------------------- 1 | LIBRARY "mydll.dll" 2 | EXETYPE NT 3 | SUBSYSTEM WINDOWS 4 | CODE SHARED EXECUTE 5 | DATA WRITE 6 | -------------------------------------------------------------------------------- /dmdsamples/mydll/mydll.di: -------------------------------------------------------------------------------- 1 | export void dllprint(); 2 | -------------------------------------------------------------------------------- /dmdsamples/mydll/test.d: -------------------------------------------------------------------------------- 1 | 2 | import mydll; 3 | 4 | int main() 5 | { 6 | mydll.dllprint(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /dmdsamples/pi.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | import std.conv; 3 | import core.stdc.stdlib; 4 | import core.stdc.time; 5 | 6 | const int LONG_TIME = 4000; 7 | 8 | byte[] p; 9 | byte[] t; 10 | int q; 11 | 12 | int main(string[] args) 13 | { 14 | time_t startime, endtime; 15 | int i; 16 | 17 | if (args.length == 2) 18 | { 19 | q = to!int(args[1]); 20 | } 21 | else 22 | { 23 | writeln("Usage: pi [precision]"); 24 | exit(55); 25 | } 26 | 27 | if (q < 0) 28 | { 29 | writeln("Precision was too low, running with precision of 0."); 30 | q = 0; 31 | } 32 | 33 | if (q > LONG_TIME) 34 | { 35 | writeln("Be prepared to wait a while..."); 36 | } 37 | 38 | // Compute one more digit than we display to compensate for rounding 39 | q++; 40 | 41 | p.length = q + 1; 42 | t.length = q + 1; 43 | 44 | /* compute pi */ 45 | core.stdc.time.time(&startime); 46 | arctan(2); 47 | arctan(3); 48 | mul4(); 49 | core.stdc.time.time(&endtime); 50 | 51 | // Return to the number of digits we want to display 52 | q--; 53 | 54 | /* print pi */ 55 | 56 | writef("pi = %d.", cast(int) (p[0])); 57 | 58 | for (i = 1; i <= q; i++) 59 | writef("%d", cast(int) (p[i])); 60 | 61 | writeln(); 62 | writefln("%s seconds to compute pi with a precision of %s digits.", endtime - startime, q); 63 | 64 | return 0; 65 | } 66 | 67 | void arctan(int s) 68 | { 69 | int n; 70 | 71 | t[0] = 1; 72 | div(s); /* t[] = 1/s */ 73 | add(); 74 | n = 1; 75 | 76 | do 77 | { 78 | mul(n); 79 | div(s * s); 80 | div(n += 2); 81 | 82 | if (((n - 1) / 2) % 2 == 0) 83 | add(); 84 | else 85 | sub(); 86 | } while (!tiszero()); 87 | } 88 | 89 | void add() 90 | { 91 | int j; 92 | 93 | for (j = q; j >= 0; j--) 94 | { 95 | if (t[j] + p[j] > 9) 96 | { 97 | p[j] += t[j] - 10; 98 | p[j - 1] += 1; 99 | } 100 | else 101 | p[j] += t[j]; 102 | } 103 | } 104 | 105 | void sub() 106 | { 107 | int j; 108 | 109 | for (j = q; j >= 0; j--) 110 | { 111 | if (p[j] < t[j]) 112 | { 113 | p[j] -= t[j] - 10; 114 | p[j - 1] -= 1; 115 | } 116 | else 117 | p[j] -= t[j]; 118 | } 119 | 120 | } 121 | 122 | void mul(int multiplier) 123 | { 124 | int b; 125 | int i; 126 | int carry = 0, digit = 0; 127 | 128 | for (i = q; i >= 0; i--) 129 | { 130 | b = (t[i] * multiplier + carry); 131 | digit = b % 10; 132 | carry = b / 10; 133 | t[i] = cast(byte) digit; 134 | } 135 | } 136 | 137 | /* t[] /= l */ 138 | void div(int divisor) 139 | { 140 | int i, b; 141 | int quotient, remainder = 0; 142 | 143 | foreach (ref x; t) 144 | { 145 | b = (10 * remainder + x); 146 | quotient = b / divisor; 147 | remainder = b % divisor; 148 | x = cast(byte) quotient; 149 | } 150 | } 151 | 152 | void div4() 153 | { 154 | int i, c, d = 0; 155 | 156 | for (i = 0; i <= q; i++) 157 | { 158 | c = (10 * d + p[i]) / 4; 159 | d = (10 * d + p[i]) % 4; 160 | p[i] = cast(byte) c; 161 | } 162 | } 163 | 164 | void mul4() 165 | { 166 | int i, c, d; 167 | 168 | d = c = 0; 169 | 170 | for (i = q; i >= 0; i--) 171 | { 172 | d = (p[i] * 4 + c) % 10; 173 | c = (p[i] * 4 + c) / 10; 174 | p[i] = cast(byte) d; 175 | } 176 | } 177 | 178 | int tiszero() 179 | { 180 | int k; 181 | 182 | for (k = 0; k <= q; k++) 183 | if (t[k] != 0) 184 | return false; 185 | 186 | return true; 187 | } 188 | -------------------------------------------------------------------------------- /dmdsamples/posix.mak: -------------------------------------------------------------------------------- 1 | ## 2 | # Example Makefile for the D programming language 3 | ## 4 | TARGETS= \ 5 | d2html \ 6 | dhry \ 7 | hello \ 8 | htmlget \ 9 | listener \ 10 | pi \ 11 | sieve \ 12 | wc \ 13 | wc2 14 | 15 | ## Those examples are Windows specific: 16 | # chello 17 | # dserver 18 | # dclient 19 | # winsamp 20 | 21 | SRC = \ 22 | chello.d \ 23 | d2html.d \ 24 | dclient.d \ 25 | dhry.d \ 26 | dserver.d \ 27 | hello.d \ 28 | htmlget.d \ 29 | listener.d \ 30 | pi.d \ 31 | sieve.d \ 32 | wc.d \ 33 | wc2.d \ 34 | winsamp.d 35 | DFLAGS = 36 | LFLAGS = 37 | 38 | 39 | ## 40 | ## Those values are immutables 41 | ## For languages such as C and C++, builtin rules are provided. 42 | ## But for D, you had to had to do everything by hand. 43 | ## Basically, if you had some Makefile knowledge, this is all you need. 44 | ## 45 | ## For explanation / more advanced use, see: 46 | ## https://www.gnu.org/software/make/manual/html_node/Suffix-Rules.html 47 | .SUFFIXES: .d 48 | .d.o: 49 | $(DMD) $(DFLAGS) -c $< -of$@ 50 | ## 51 | 52 | LINK = dmd 53 | DMD = dmd 54 | RM = rm -rf 55 | OBJS = $(SRC:.d=.o) 56 | 57 | all: $(TARGETS) 58 | 59 | clean: 60 | $(RM) $(OBJS) 61 | 62 | fclean: clean 63 | $(RM) $(TARGETS) 64 | $(RM) *.d.htm 65 | 66 | re: fclean all 67 | 68 | chello: $(OBJS) 69 | $(LINK) $(LFLAGS) $(OBJS) -of$@ 70 | 71 | .PHONY: all clean fclean re 72 | .NOTPARALLEL: clean 73 | 74 | d2html: d2html.o 75 | $(LINK) $(LFLAGS) $< -of$@ 76 | 77 | dclient: dclient.o 78 | $(LINK) $(LFLAGS) $< -of$@ 79 | 80 | dhry: dhry.o 81 | $(LINK) $(LFLAGS) $< -of$@ 82 | 83 | dserver: dserver.o 84 | $(LINK) $(LFLAGS) $< -of$@ 85 | 86 | hello: hello.o 87 | $(LINK) $(LFLAGS) $< -of$@ 88 | 89 | htmlget: htmlget.o 90 | $(LINK) $(LFLAGS) $< -of$@ 91 | 92 | listener: listener.o 93 | $(LINK) $(LFLAGS) $< -of$@ 94 | 95 | pi: pi.o 96 | $(LINK) $(LFLAGS) $< -of$@ 97 | 98 | sieve: sieve.o 99 | $(LINK) $(LFLAGS) $< -of$@ 100 | 101 | wc2: wc2.o 102 | $(LINK) $(LFLAGS) $< -of$@ 103 | 104 | wc: wc.o 105 | $(LINK) $(LFLAGS) $< -of$@ 106 | 107 | winsamp: winsamp.o 108 | $(LINK) $(LFLAGS) $< -of$@ 109 | -------------------------------------------------------------------------------- /dmdsamples/sieve.d: -------------------------------------------------------------------------------- 1 | /* Eratosthenes Sieve prime number calculation. */ 2 | 3 | import std.conv; 4 | import std.stdio; 5 | import std.range; 6 | 7 | void main(string[] args) 8 | { 9 | immutable max = (1 < args.length) 10 | ? args[1].to!size_t 11 | : 0x4000; 12 | size_t count = 1; // we have 2. 13 | // flags[i] = isPrime(2 * i + 3) 14 | auto flags = new bool[(max - 1) / 2]; 15 | flags[] = true; 16 | 17 | foreach (i; 0..flags.length) 18 | { 19 | if (!flags[i]) 20 | continue; 21 | auto prime = i + i + 3; 22 | foreach (k; iota(i + prime, flags.length, prime)) 23 | flags[k] = false; 24 | 25 | count++; 26 | } 27 | writefln("%d primes", count); 28 | } 29 | -------------------------------------------------------------------------------- /dmdsamples/wc.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | import std.file; 3 | 4 | void main(string[] args) 5 | { 6 | int w_total; 7 | int l_total; 8 | int c_total; 9 | 10 | writeln(" lines words bytes file"); 11 | 12 | foreach (arg; args[1 .. $]) 13 | { 14 | int w_cnt, l_cnt, c_cnt; 15 | bool inword; 16 | 17 | string input = readText(arg); 18 | 19 | foreach (char c; input) 20 | { 21 | if (c == '\n') 22 | ++l_cnt; 23 | 24 | if (c != ' ') 25 | { 26 | if (!inword) 27 | { 28 | inword = true; 29 | ++w_cnt; 30 | } 31 | } 32 | else 33 | inword = false; 34 | 35 | ++c_cnt; 36 | } 37 | 38 | writefln("%8s%8s%8s %s\n", l_cnt, w_cnt, c_cnt, arg); 39 | l_total += l_cnt; 40 | w_total += w_cnt; 41 | c_total += c_cnt; 42 | } 43 | 44 | if (args.length > 2) 45 | { 46 | writefln("--------------------------------------\n%8s%8s%8s total", 47 | l_total, w_total, c_total); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dmdsamples/wc2.d: -------------------------------------------------------------------------------- 1 | import std.stdio; 2 | import std.file; 3 | import std.algorithm.sorting; 4 | 5 | void main (string[] args) 6 | { 7 | int w_total; 8 | int l_total; 9 | ulong c_total; 10 | size_t[string] dictionary; 11 | 12 | writefln(" lines words bytes file"); 13 | foreach (arg; args[1 .. $]) 14 | { 15 | int w_cnt, l_cnt; 16 | bool inword; 17 | auto c_cnt = std.file.getSize(arg); 18 | 19 | if (c_cnt < 10_000_000) 20 | { 21 | size_t wstart; 22 | auto input = readText(arg); 23 | 24 | foreach (j, c; input) 25 | { 26 | if (c == '\n') 27 | ++l_cnt; 28 | if (c >= '0' && c <= '9') 29 | { 30 | } 31 | else if (c >= 'a' && c <= 'z' || 32 | c >= 'A' && c <= 'Z') 33 | { 34 | if (!inword) 35 | { 36 | wstart = j; 37 | inword = true; 38 | ++w_cnt; 39 | } 40 | } 41 | else if (inword) 42 | { 43 | auto word = input[wstart .. j]; 44 | dictionary[word]++; 45 | inword = false; 46 | } 47 | } 48 | if (inword) 49 | { 50 | auto w = input[wstart .. $]; 51 | dictionary[w]++; 52 | } 53 | } 54 | else 55 | { 56 | auto f = std.stdio.File(arg); 57 | string buf; 58 | 59 | while (!f.eof()) 60 | { 61 | char c; 62 | f.readf("%c", &c); 63 | 64 | if (c == '\n') 65 | ++l_cnt; 66 | 67 | if (c >= '0' && c <= '9') 68 | { 69 | if (inword) 70 | buf ~= c; 71 | } 72 | else if (c >= 'a' && c <= 'z' || 73 | c >= 'A' && c <= 'Z') 74 | { 75 | if (!inword) 76 | { 77 | buf.length = 0; 78 | buf ~= c; 79 | inword = 1; 80 | ++w_cnt; 81 | } 82 | else 83 | buf ~= c; 84 | } 85 | else if (inword) 86 | { 87 | if (++dictionary[buf] == 1) 88 | buf = null; 89 | inword = 0; 90 | } 91 | } 92 | 93 | if (inword) 94 | { 95 | dictionary[buf]++; 96 | } 97 | } 98 | 99 | writefln("%8s%8s%8s %s\n", l_cnt, w_cnt, c_cnt, arg); 100 | l_total += l_cnt; 101 | w_total += w_cnt; 102 | c_total += c_cnt; 103 | } 104 | 105 | if (args.length > 2) 106 | { 107 | writefln("--------------------------------------\n%8s%8s%8s total", 108 | l_total, w_total, c_total); 109 | } 110 | 111 | writefln("--------------------------------------"); 112 | 113 | foreach (word1; dictionary.keys.sort()) 114 | { 115 | writefln("%3s %s", dictionary[word1], word1); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /dmdsamples/win32.mak: -------------------------------------------------------------------------------- 1 | MODEL=32 2 | DMD=..\..\windows\bin\dmd 3 | DFLAGS=-m$(MODEL) 4 | 5 | EXAMPLES = hello d2html dhry pi sieve wc wc2 \ 6 | winsamp dserver mydll htmlget listener 7 | 8 | all: $(EXAMPLES) 9 | echo done 10 | 11 | d2html: 12 | $(DMD) d2html $(DFLAGS) 13 | .\d2html.exe d2html.d 14 | 15 | dhry: 16 | $(DMD) dhry $(DFLAGS) 17 | .\dhry.exe 18 | 19 | hello: 20 | $(DMD) hello $(DFLAGS) 21 | .\hello.exe 22 | 23 | htmlget: 24 | $(DMD) htmlget $(DFLAGS) 25 | .\htmlget.exe www.dlang.org/index.html 26 | 27 | listener: 28 | $(DMD) listener $(DFLAGS) 29 | # .\listener.exe 30 | 31 | pi: 32 | $(DMD) pi $(DFLAGS) 33 | .\pi.exe 1000 34 | 35 | sieve: 36 | $(DMD) sieve $(DFLAGS) 37 | .\sieve.exe 38 | 39 | wc: 40 | $(DMD) wc $(DFLAGS) 41 | .\wc.exe wc.d 42 | 43 | wc2: 44 | $(DMD) wc2 $(DFLAGS) 45 | .\wc2.exe wc2.d 46 | 47 | winsamp: 48 | $(DMD) winsamp $(DFLAGS) gdi32.lib user32.lib winsamp.def 49 | # .\winsamp.exe 50 | 51 | # COM client/server example 52 | # dclient will fail unless run with administrator rights 53 | dserver: 54 | $(DMD) dserver.d chello.d $(DFLAGS) -L/DLL dserver64.def advapi32.lib ole32.lib user32.lib 55 | $(DMD) dclient $(DFLAGS) ole32.lib uuid.lib 56 | .\dclient.exe 57 | 58 | mydll: 59 | $(DMD) $(DFLAGS) -ofmydll.dll mydll\mydll.d mydll\dll.d -L/DLL 60 | $(DMD) $(DFLAGS) -ofdlltest.exe mydll\test.d mydll\mydll.di mydll.lib 61 | .\dlltest.exe 62 | 63 | clean: 64 | clean.bat 65 | -------------------------------------------------------------------------------- /dmdsamples/winsamp.d: -------------------------------------------------------------------------------- 1 | module winsamp; 2 | 3 | /+ Compile with: 4 | + dmd winsamp winsamp.def 5 | + or: 6 | + dmd winsamp -L-Subsystem:Windows 7 | + 8 | + 64 bit version: 9 | + dmd -m64 winsamp -L-Subsystem:Windows user32.lib 10 | +/ 11 | 12 | pragma(lib, "gdi32.lib"); 13 | import core.runtime; 14 | import core.sys.windows.windef; 15 | import core.sys.windows.wingdi; 16 | import core.sys.windows.winuser; 17 | import std.string; 18 | 19 | enum IDC_BTNCLICK = 101; 20 | enum IDC_BTNDONTCLICK = 102; 21 | 22 | extern(Windows) 23 | int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) 24 | { 25 | int result; 26 | 27 | try 28 | { 29 | Runtime.initialize(); 30 | result = myWinMain(hInstance, hPrevInstance, lpCmdLine, iCmdShow); 31 | Runtime.terminate(); 32 | } 33 | catch (Throwable e) 34 | { 35 | MessageBoxA(null, e.toString().toStringz, "Error", MB_OK | MB_ICONEXCLAMATION); 36 | result = 0; 37 | } 38 | 39 | return result; 40 | } 41 | 42 | int myWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int iCmdShow) 43 | { 44 | wstring caption = "The Hello Program"; 45 | wstring className = "DWndClass"; 46 | HWND hWnd, btnClick, btnDontClick; 47 | MSG msg; 48 | WNDCLASSW wndclass; 49 | 50 | wndclass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; 51 | wndclass.lpfnWndProc = &WindowProc; 52 | wndclass.cbClsExtra = 0; 53 | wndclass.cbWndExtra = 0; 54 | wndclass.hInstance = hInstance; 55 | wndclass.hIcon = LoadIconW(null, IDI_APPLICATION); 56 | wndclass.hCursor = LoadCursorW(null, IDC_CROSS); 57 | wndclass.hbrBackground = cast(HBRUSH)GetStockObject(WHITE_BRUSH); 58 | wndclass.lpszMenuName = null; 59 | wndclass.lpszClassName = className.ptr; 60 | 61 | if (!RegisterClassW(&wndclass)) 62 | { 63 | MessageBoxW(null, "Couldn't register Window Class!", caption.ptr, MB_ICONERROR); 64 | return 0; 65 | } 66 | 67 | hWnd = CreateWindowW(className.ptr, // window class name 68 | caption.ptr, // window caption 69 | WS_THICKFRAME | 70 | WS_MAXIMIZEBOX | 71 | WS_MINIMIZEBOX | 72 | WS_SYSMENU | 73 | WS_VISIBLE, // window style 74 | CW_USEDEFAULT, // initial x position 75 | CW_USEDEFAULT, // initial y position 76 | 600, // initial x size 77 | 400, // initial y size 78 | HWND_DESKTOP, // parent window handle 79 | null, // window menu handle 80 | hInstance, // program instance handle 81 | null); // creation parameters 82 | 83 | if (hWnd is null) 84 | { 85 | MessageBoxW(null, "Couldn't create window.", caption.ptr, MB_ICONERROR); 86 | return 0; 87 | } 88 | 89 | btnClick = CreateWindowW("BUTTON", "Click Me", WS_CHILD | WS_VISIBLE, 90 | 0, 0, 100, 25, hWnd, cast(HMENU)IDC_BTNCLICK, hInstance, null); 91 | 92 | btnDontClick = CreateWindowW("BUTTON", "DON'T CLICK!", WS_CHILD | WS_VISIBLE, 93 | 110, 0, 100, 25, hWnd, cast(HMENU)IDC_BTNDONTCLICK, hInstance, null); 94 | 95 | ShowWindow(hWnd, iCmdShow); 96 | UpdateWindow(hWnd); 97 | 98 | while (GetMessageW(&msg, null, 0, 0)) 99 | { 100 | TranslateMessage(&msg); 101 | DispatchMessageW(&msg); 102 | } 103 | 104 | return cast(int) msg.wParam; 105 | } 106 | 107 | int* p; 108 | extern(Windows) 109 | LRESULT WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) nothrow 110 | { 111 | switch (message) 112 | { 113 | case WM_COMMAND: 114 | { 115 | switch (LOWORD(wParam)) 116 | { 117 | case IDC_BTNCLICK: 118 | if (HIWORD(wParam) == BN_CLICKED) 119 | MessageBoxW(hWnd, "Hello, world!", "Greeting", 120 | MB_OK | MB_ICONINFORMATION); 121 | 122 | break; 123 | 124 | case IDC_BTNDONTCLICK: 125 | if (HIWORD(wParam) == BN_CLICKED) 126 | { 127 | MessageBoxW(hWnd, "You've been warned...", "Prepare to GP fault", 128 | MB_OK | MB_ICONEXCLAMATION); 129 | *p = 1; 130 | } 131 | 132 | break; 133 | 134 | default: 135 | } 136 | 137 | break; 138 | } 139 | 140 | case WM_PAINT: 141 | { 142 | enum text = "D Does Windows"; 143 | PAINTSTRUCT ps; 144 | 145 | HDC dc = BeginPaint(hWnd, &ps); 146 | scope(exit) EndPaint(hWnd, &ps); 147 | RECT r; 148 | GetClientRect(hWnd, &r); 149 | HFONT font = CreateFontW(80, 0, 0, 0, FW_EXTRABOLD, FALSE, FALSE, 150 | FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, 151 | DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); 152 | HGDIOBJ old = SelectObject(dc, cast(HGDIOBJ) font); 153 | SetTextAlign(dc, TA_CENTER | TA_BASELINE); 154 | TextOutA(dc, r.right / 2, r.bottom / 2, text.ptr, text.length); 155 | DeleteObject(SelectObject(dc, old)); 156 | 157 | break; 158 | } 159 | 160 | case WM_DESTROY: 161 | PostQuitMessage(0); 162 | break; 163 | 164 | default: 165 | break; 166 | } 167 | 168 | return DefWindowProcW(hWnd, message, wParam, lParam); 169 | } 170 | -------------------------------------------------------------------------------- /dmdsamples/winsamp.def: -------------------------------------------------------------------------------- 1 | EXETYPE NT 2 | SUBSYSTEM WINDOWS 3 | -------------------------------------------------------------------------------- /dub.sdl: -------------------------------------------------------------------------------- 1 | name "undead" 2 | description "Obsolete Phobos modules, back from the dead" 3 | homepage "https://github.com/dlang/undeaD" 4 | authors "various" 5 | license "BSL-1.0" 6 | targetType "library" 7 | targetPath "bin" 8 | buildType "unittest" { 9 | buildOptions "debugMode" "debugInfo" "unittests" "deprecationErrors" "warningsAsErrors" 10 | } 11 | -------------------------------------------------------------------------------- /examples/hello-from-the-dead/dub.sdl: -------------------------------------------------------------------------------- 1 | name "hello-from-the-dead" 2 | description "A test program that uses undeaD" 3 | authors "Petar Kirov" 4 | copyright "Copyright © 2020, Petar Kirov" 5 | license "BSL-1.0" 6 | dependency "undead" version="*" path="../.." 7 | targetPath "bin" 8 | -------------------------------------------------------------------------------- /examples/hello-from-the-dead/source/app.d: -------------------------------------------------------------------------------- 1 | static import std.string; 2 | 3 | void main() 4 | { 5 | import undead.regexp : RegExp, sub; 6 | import std.stdio : writeln; 7 | 8 | string foo(RegExp r) { return "ss"; } 9 | 10 | auto r = sub("hello", "ll", delegate string(RegExp r) { return "ss"; }); 11 | assert(r == "hesso"); 12 | 13 | r = sub("hello", "l", delegate string(RegExp r) { return "l"; }, "g"); 14 | assert(r == "hello"); 15 | 16 | auto s = sub("Strap a rocket engine on a chicken.", 17 | "[ar]", 18 | delegate string (RegExp m) 19 | { 20 | return std.string.toUpper(m[0]); 21 | }, 22 | "g"); 23 | assert(s == "StRAp A Rocket engine on A chicken."); 24 | s.writeln; 25 | } 26 | -------------------------------------------------------------------------------- /posix.mak: -------------------------------------------------------------------------------- 1 | #_ posix.mak 2 | # Build posix version of undead 3 | # Needs Digital Mars D compiler to build, available free from: 4 | # http://www.digitalmars.com/d/ 5 | 6 | DMD=dmd 7 | DEL=rm 8 | S=src/undead 9 | O=obj 10 | B=bin 11 | 12 | TARGET=undead 13 | 14 | DFLAGS=-g -Isrc/ 15 | LFLAGS=-L/map/co 16 | #DFLAGS= 17 | #LFLAGS= 18 | 19 | .d.obj : 20 | $(DMD) -c $(DFLAGS) $* 21 | 22 | SRC= $S/bitarray.d $S/regexp.d $S/datebase.d $S/date.d $S/dateparse.d \ 23 | $S/cstream.d $S/stream.d $S/socketstream.d $S/doformat.d $S/string.d \ 24 | $S/internal/file.d 25 | 26 | 27 | SOURCE= $(SRC) win32.mak posix.mak LICENSE README.md dub.json 28 | 29 | all: $B/$(TARGET).a 30 | 31 | ################################################# 32 | 33 | $B/$(TARGET).a : $(SRC) 34 | $(DMD) -lib -of$B/$(TARGET).a $(SRC) $(DFLAGS) 35 | 36 | 37 | unittest : 38 | $(DMD) -unittest -main -cov -of$O/unittest $(SRC) $(DFLAGS) 39 | $O/unittest 40 | 41 | 42 | clean: 43 | $(DEL) $O/unittest *.lst 44 | 45 | 46 | tolf: 47 | tolf $(SOURCE) 48 | 49 | 50 | detab: 51 | detab $(SRC) 52 | 53 | 54 | zip: detab tolf $(SOURCE) 55 | $(DEL) undead.zip 56 | zip undead $(SOURCE) 57 | 58 | gitzip: 59 | git archive --format=zip HEAD > undead.zip 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/undead/bitarray.d: -------------------------------------------------------------------------------- 1 | /*********************** 2 | * Source: $(PHOBOSSRC std/_bitarray.d) 3 | * Macros: 4 | * WIKI = StdBitarray 5 | */ 6 | 7 | module undead.bitarray; 8 | 9 | //debug = bitarray; // uncomment to turn on debugging printf's 10 | 11 | private import core.bitop; 12 | 13 | /** 14 | * An array of bits. 15 | */ 16 | 17 | struct BitArray 18 | { 19 | size_t len; 20 | size_t* ptr; 21 | 22 | size_t dim() 23 | { 24 | return (len + 31) / 32; 25 | } 26 | 27 | size_t length() const pure nothrow 28 | { 29 | return len; 30 | } 31 | 32 | void length(size_t newlen) 33 | { 34 | if (newlen != len) 35 | { 36 | size_t olddim = dim(); 37 | size_t newdim = (newlen + 31) / 32; 38 | 39 | if (newdim != olddim) 40 | { 41 | // Create a fake array so we can use D's realloc machinery 42 | auto b = ptr[0 .. olddim]; 43 | b.length = newdim; // realloc 44 | ptr = b.ptr; 45 | if (newdim & 31) 46 | { // Set any pad bits to 0 47 | ptr[newdim - 1] &= ~(~0 << (newdim & 31)); 48 | } 49 | } 50 | 51 | len = newlen; 52 | } 53 | } 54 | 55 | /********************************************** 56 | * Support for [$(I index)] operation for BitArray. 57 | */ 58 | bool opIndex(size_t i) 59 | in 60 | { 61 | assert(i < len); 62 | } 63 | do 64 | { 65 | return cast(bool)bt(ptr, i); 66 | } 67 | 68 | /** ditto */ 69 | bool opIndexAssign(bool b, size_t i) 70 | in 71 | { 72 | assert(i < len); 73 | } 74 | do 75 | { 76 | if (b) 77 | bts(ptr, i); 78 | else 79 | btr(ptr, i); 80 | return b; 81 | } 82 | 83 | /********************************************** 84 | * Support for array.dup property for BitArray. 85 | */ 86 | BitArray dup() 87 | { 88 | BitArray ba; 89 | 90 | auto b = ptr[0 .. dim].dup; 91 | ba.len = len; 92 | ba.ptr = b.ptr; 93 | return ba; 94 | } 95 | 96 | unittest 97 | { 98 | BitArray a; 99 | BitArray b; 100 | 101 | debug(bitarray) printf("BitArray.dup.unittest\n"); 102 | 103 | a.length = 3; 104 | a[0] = 1; a[1] = 0; a[2] = 1; 105 | b = a.dup; 106 | assert(b.length == 3); 107 | for (int i = 0; i < 3; i++) 108 | { debug(bitarray) printf("b[%d] = %d\n", i, b[i]); 109 | assert(b[i] == (((i ^ 1) & 1) ? true : false)); 110 | } 111 | } 112 | 113 | /********************************************** 114 | * Support for foreach loops for BitArray. 115 | */ 116 | int opApply(int delegate(ref bool) dg) 117 | { 118 | int result; 119 | 120 | for (size_t i = 0; i < len; i++) 121 | { bool b = opIndex(i); 122 | result = dg(b); 123 | (this)[i] = b; 124 | if (result) 125 | break; 126 | } 127 | return result; 128 | } 129 | 130 | /** ditto */ 131 | int opApply(int delegate(ref size_t, ref bool) dg) 132 | { 133 | int result; 134 | 135 | for (size_t i = 0; i < len; i++) 136 | { bool b = opIndex(i); 137 | result = dg(i, b); 138 | (this)[i] = b; 139 | if (result) 140 | break; 141 | } 142 | return result; 143 | } 144 | 145 | unittest 146 | { 147 | debug(bitarray) printf("BitArray.opApply unittest\n"); 148 | 149 | static bool[] ba = [1,0,1]; 150 | 151 | BitArray a; a.init(ba); 152 | 153 | int i; 154 | foreach (b;a) 155 | { 156 | switch (i) 157 | { case 0: assert(b == true); break; 158 | case 1: assert(b == false); break; 159 | case 2: assert(b == true); break; 160 | default: assert(0); 161 | } 162 | i++; 163 | } 164 | 165 | foreach (j,b;a) 166 | { 167 | switch (j) 168 | { case 0: assert(b == true); break; 169 | case 1: assert(b == false); break; 170 | case 2: assert(b == true); break; 171 | default: assert(0); 172 | } 173 | } 174 | } 175 | 176 | 177 | /********************************************** 178 | * Support for array.reverse property for BitArray. 179 | */ 180 | 181 | BitArray reverse() 182 | out (result) 183 | { 184 | assert(result == this); 185 | } 186 | do 187 | { 188 | if (len >= 2) 189 | { 190 | bool t; 191 | size_t lo, hi; 192 | 193 | lo = 0; 194 | hi = len - 1; 195 | for (; lo < hi; lo++, hi--) 196 | { 197 | t = (this)[lo]; 198 | (this)[lo] = (this)[hi]; 199 | (this)[hi] = t; 200 | } 201 | } 202 | return this; 203 | } 204 | 205 | unittest 206 | { 207 | debug(bitarray) printf("BitArray.reverse.unittest\n"); 208 | 209 | BitArray b; 210 | static bool[5] data = [1,0,1,1,0]; 211 | int i; 212 | 213 | b.init(data); 214 | b.reverse; 215 | for (i = 0; i < data.length; i++) 216 | { 217 | assert(b[i] == data[4 - i]); 218 | } 219 | } 220 | 221 | 222 | /********************************************** 223 | * Support for array.sort property for BitArray. 224 | */ 225 | 226 | BitArray sort() 227 | out (result) 228 | { 229 | assert(result == this); 230 | } 231 | do 232 | { 233 | if (len >= 2) 234 | { 235 | size_t lo, hi; 236 | 237 | lo = 0; 238 | hi = len - 1; 239 | while (1) 240 | { 241 | while (1) 242 | { 243 | if (lo >= hi) 244 | goto Ldone; 245 | if ((this)[lo] == true) 246 | break; 247 | lo++; 248 | } 249 | 250 | while (1) 251 | { 252 | if (lo >= hi) 253 | goto Ldone; 254 | if ((this)[hi] == false) 255 | break; 256 | hi--; 257 | } 258 | 259 | (this)[lo] = false; 260 | (this)[hi] = true; 261 | 262 | lo++; 263 | hi--; 264 | } 265 | Ldone: 266 | ; 267 | } 268 | return this; 269 | } 270 | 271 | unittest 272 | { 273 | debug(bitarray) printf("BitArray.sort.unittest\n"); 274 | 275 | __gshared size_t x = 0b1100011000; 276 | __gshared BitArray ba = { 10, &x }; 277 | ba.sort; 278 | for (size_t i = 0; i < 6; i++) 279 | assert(ba[i] == false); 280 | for (size_t i = 6; i < 10; i++) 281 | assert(ba[i] == true); 282 | } 283 | 284 | 285 | /*************************************** 286 | * Support for operators == and != for bit arrays. 287 | */ 288 | 289 | bool opEquals(const ref BitArray a2) const pure nothrow 290 | { size_t i; 291 | 292 | if (this.length != a2.length) 293 | return false; // not equal 294 | byte *p1 = cast(byte*)this.ptr; 295 | byte *p2 = cast(byte*)a2.ptr; 296 | auto n = this.length / 8; 297 | for (i = 0; i < n; i++) 298 | { 299 | if (p1[i] != p2[i]) 300 | return false; // not equal 301 | } 302 | 303 | n = this.length & 7; 304 | auto mask = cast(ubyte)((1 << n) - 1); 305 | //printf("i = %d, n = %d, mask = %x, %x, %x\n", i, n, mask, p1[i], p2[i]); 306 | return (mask == 0) || (p1[i] & mask) == (p2[i] & mask); 307 | } 308 | 309 | unittest 310 | { 311 | debug(bitarray) printf("BitArray.opEquals unittest\n"); 312 | 313 | static bool[] ba = [1,0,1,0,1]; 314 | static bool[] bb = [1,0,1]; 315 | static bool[] bc = [1,0,1,0,1,0,1]; 316 | static bool[] bd = [1,0,1,1,1]; 317 | static bool[] be = [1,0,1,0,1]; 318 | 319 | BitArray a; a.init(ba); 320 | BitArray b; b.init(bb); 321 | BitArray c; c.init(bc); 322 | BitArray d; d.init(bd); 323 | BitArray e; e.init(be); 324 | 325 | assert(a != b); 326 | assert(a != c); 327 | assert(a != d); 328 | assert(a == e); 329 | } 330 | 331 | /*************************************** 332 | * Implement comparison operators. 333 | */ 334 | 335 | int opCmp(const ref BitArray a2) const pure nothrow 336 | { 337 | size_t i; 338 | 339 | auto len = this.length; 340 | if (a2.length < len) 341 | len = a2.length; 342 | auto p1 = cast(ubyte*)this.ptr; 343 | auto p2 = cast(ubyte*)a2.ptr; 344 | auto n = len / 8; 345 | for (i = 0; i < n; i++) 346 | { 347 | if (p1[i] != p2[i]) 348 | break; // not equal 349 | } 350 | for (auto j = i * 8; j < len; j++) 351 | { auto mask = cast(ubyte)(1 << j); 352 | 353 | auto c = cast(int)(p1[i] & mask) - cast(int)(p2[i] & mask); 354 | if (c) 355 | return c; 356 | } 357 | version (D_LP64) 358 | { 359 | long c = this.len - a2.length; 360 | if (c < 0) 361 | return -1; 362 | else 363 | return c != 0; 364 | } 365 | else 366 | return cast(int)this.len - cast(int)a2.length; 367 | } 368 | 369 | unittest 370 | { 371 | debug(bitarray) printf("BitArray.opCmp unittest\n"); 372 | 373 | static bool[] ba = [1,0,1,0,1]; 374 | static bool[] bb = [1,0,1]; 375 | static bool[] bc = [1,0,1,0,1,0,1]; 376 | static bool[] bd = [1,0,1,1,1]; 377 | static bool[] be = [1,0,1,0,1]; 378 | 379 | BitArray a; a.init(ba); 380 | BitArray b; b.init(bb); 381 | BitArray c; c.init(bc); 382 | BitArray d; d.init(bd); 383 | BitArray e; e.init(be); 384 | 385 | assert(a > b); 386 | assert(a >= b); 387 | assert(a < c); 388 | assert(a <= c); 389 | assert(a < d); 390 | assert(a <= d); 391 | assert(a == e); 392 | assert(a <= e); 393 | assert(a >= e); 394 | } 395 | 396 | /*************************************** 397 | * Set BitArray to contents of ba[] 398 | */ 399 | 400 | void init(bool[] ba) 401 | { 402 | length = ba.length; 403 | foreach (i, b; ba) 404 | { 405 | (this)[i] = b; 406 | } 407 | } 408 | 409 | 410 | /*************************************** 411 | * Map BitArray onto v[], with numbits being the number of bits 412 | * in the array. Does not copy the data. 413 | * 414 | * This is the inverse of opCast. 415 | */ 416 | void init(void[] v, size_t numbits) 417 | in 418 | { 419 | assert(numbits <= v.length * 8); 420 | assert((v.length & 3) == 0); 421 | } 422 | do 423 | { 424 | ptr = cast(typeof(ptr))v.ptr; 425 | len = numbits; 426 | } 427 | 428 | unittest 429 | { 430 | debug(bitarray) printf("BitArray.init unittest\n"); 431 | 432 | static bool[] ba = [1,0,1,0,1]; 433 | 434 | BitArray a; a.init(ba); 435 | BitArray b; 436 | void[] v; 437 | 438 | v = cast(void[])a; 439 | b.init(v, a.length); 440 | 441 | assert(b[0] == 1); 442 | assert(b[1] == 0); 443 | assert(b[2] == 1); 444 | assert(b[3] == 0); 445 | assert(b[4] == 1); 446 | 447 | a[0] = 0; 448 | assert(b[0] == 0); 449 | 450 | assert(a == b); 451 | } 452 | 453 | /*************************************** 454 | * Convert to void[]. 455 | */ 456 | void[] opCast() 457 | { 458 | return cast(void[])ptr[0 .. dim]; 459 | } 460 | 461 | unittest 462 | { 463 | debug(bitarray) printf("BitArray.opCast unittest\n"); 464 | 465 | static bool[] ba = [1,0,1,0,1]; 466 | 467 | BitArray a; a.init(ba); 468 | void[] v = cast(void[])a; 469 | 470 | assert(v.length == a.dim * size_t.sizeof); 471 | } 472 | 473 | /*************************************** 474 | * Support for unary operator ~ for bit arrays. 475 | */ 476 | BitArray opUnary(string op : "~")() 477 | { 478 | auto dim = this.dim(); 479 | 480 | BitArray result; 481 | 482 | result.length = len; 483 | for (size_t i = 0; i < dim; i++) 484 | result.ptr[i] = ~this.ptr[i]; 485 | if (len & 31) 486 | result.ptr[dim - 1] &= ~(~0 << (len & 31)); 487 | return result; 488 | } 489 | 490 | unittest 491 | { 492 | debug(bitarray) printf("BitArray.opUnary unittest\n"); 493 | 494 | static bool[] ba = [1,0,1,0,1]; 495 | 496 | BitArray a; a.init(ba); 497 | BitArray b = ~a; 498 | 499 | assert(b[0] == 0); 500 | assert(b[1] == 1); 501 | assert(b[2] == 0); 502 | assert(b[3] == 1); 503 | assert(b[4] == 0); 504 | } 505 | 506 | 507 | /*************************************** 508 | * Support for binary operator & for bit arrays. 509 | */ 510 | BitArray opBinary(string op : "&")(BitArray e2) 511 | in 512 | { 513 | assert(len == e2.length); 514 | } 515 | do 516 | { 517 | auto dim = this.dim(); 518 | 519 | BitArray result; 520 | 521 | result.length = len; 522 | for (size_t i = 0; i < dim; i++) 523 | result.ptr[i] = this.ptr[i] & e2.ptr[i]; 524 | return result; 525 | } 526 | 527 | unittest 528 | { 529 | debug(bitarray) printf("BitArray.opBinary unittest\n"); 530 | 531 | static bool[] ba = [1,0,1,0,1]; 532 | static bool[] bb = [1,0,1,1,0]; 533 | 534 | BitArray a; a.init(ba); 535 | BitArray b; b.init(bb); 536 | 537 | BitArray c = a & b; 538 | 539 | assert(c[0] == 1); 540 | assert(c[1] == 0); 541 | assert(c[2] == 1); 542 | assert(c[3] == 0); 543 | assert(c[4] == 0); 544 | } 545 | 546 | 547 | /*************************************** 548 | * Support for binary operator | for bit arrays. 549 | */ 550 | BitArray opBinary(string op : "|")(BitArray e2) 551 | in 552 | { 553 | assert(len == e2.length); 554 | } 555 | do 556 | { 557 | auto dim = this.dim(); 558 | 559 | BitArray result; 560 | 561 | result.length = len; 562 | for (size_t i = 0; i < dim; i++) 563 | result.ptr[i] = this.ptr[i] | e2.ptr[i]; 564 | return result; 565 | } 566 | 567 | unittest 568 | { 569 | debug(bitarray) printf("BitArray.opBinary unittest\n"); 570 | 571 | static bool[] ba = [1,0,1,0,1]; 572 | static bool[] bb = [1,0,1,1,0]; 573 | 574 | BitArray a; a.init(ba); 575 | BitArray b; b.init(bb); 576 | 577 | BitArray c = a | b; 578 | 579 | assert(c[0] == 1); 580 | assert(c[1] == 0); 581 | assert(c[2] == 1); 582 | assert(c[3] == 1); 583 | assert(c[4] == 1); 584 | } 585 | 586 | 587 | /*************************************** 588 | * Support for binary operator ^ for bit arrays. 589 | */ 590 | BitArray opBinary(string op : "^")(BitArray e2) 591 | in 592 | { 593 | assert(len == e2.length); 594 | } 595 | do 596 | { 597 | auto dim = this.dim(); 598 | 599 | BitArray result; 600 | 601 | result.length = len; 602 | for (size_t i = 0; i < dim; i++) 603 | result.ptr[i] = this.ptr[i] ^ e2.ptr[i]; 604 | return result; 605 | } 606 | 607 | unittest 608 | { 609 | debug(bitarray) printf("BitArray.opBinary unittest\n"); 610 | 611 | static bool[] ba = [1,0,1,0,1]; 612 | static bool[] bb = [1,0,1,1,0]; 613 | 614 | BitArray a; a.init(ba); 615 | BitArray b; b.init(bb); 616 | 617 | BitArray c = a ^ b; 618 | 619 | assert(c[0] == 0); 620 | assert(c[1] == 0); 621 | assert(c[2] == 0); 622 | assert(c[3] == 1); 623 | assert(c[4] == 1); 624 | } 625 | 626 | 627 | /*************************************** 628 | * Support for binary operator - for bit arrays. 629 | * 630 | * $(I a - b) for BitArrays means the same thing as $(I a & ~b). 631 | */ 632 | BitArray opBinary(string op : "-")(BitArray e2) 633 | in 634 | { 635 | assert(len == e2.length); 636 | } 637 | do 638 | { 639 | auto dim = this.dim(); 640 | 641 | BitArray result; 642 | 643 | result.length = len; 644 | for (size_t i = 0; i < dim; i++) 645 | result.ptr[i] = this.ptr[i] & ~e2.ptr[i]; 646 | return result; 647 | } 648 | 649 | unittest 650 | { 651 | debug(bitarray) printf("BitArray.opBinary unittest\n"); 652 | 653 | static bool[] ba = [1,0,1,0,1]; 654 | static bool[] bb = [1,0,1,1,0]; 655 | 656 | BitArray a; a.init(ba); 657 | BitArray b; b.init(bb); 658 | 659 | BitArray c = a - b; 660 | 661 | assert(c[0] == 0); 662 | assert(c[1] == 0); 663 | assert(c[2] == 0); 664 | assert(c[3] == 0); 665 | assert(c[4] == 1); 666 | } 667 | 668 | 669 | /*************************************** 670 | * Support for operator &= bit arrays. 671 | */ 672 | BitArray opOpAssign(string op : "&")(BitArray e2) 673 | in 674 | { 675 | assert(len == e2.length); 676 | } 677 | do 678 | { 679 | auto dim = this.dim(); 680 | 681 | for (size_t i = 0; i < dim; i++) 682 | ptr[i] &= e2.ptr[i]; 683 | return this; 684 | } 685 | 686 | unittest 687 | { 688 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 689 | 690 | static bool[] ba = [1,0,1,0,1]; 691 | static bool[] bb = [1,0,1,1,0]; 692 | 693 | BitArray a; a.init(ba); 694 | BitArray b; b.init(bb); 695 | 696 | a &= b; 697 | assert(a[0] == 1); 698 | assert(a[1] == 0); 699 | assert(a[2] == 1); 700 | assert(a[3] == 0); 701 | assert(a[4] == 0); 702 | } 703 | 704 | 705 | /*************************************** 706 | * Support for operator |= for bit arrays. 707 | */ 708 | BitArray opOpAssign(string op : "|")(BitArray e2) 709 | in 710 | { 711 | assert(len == e2.length); 712 | } 713 | do 714 | { 715 | auto dim = this.dim(); 716 | 717 | for (size_t i = 0; i < dim; i++) 718 | ptr[i] |= e2.ptr[i]; 719 | return this; 720 | } 721 | 722 | unittest 723 | { 724 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 725 | 726 | static bool[] ba = [1,0,1,0,1]; 727 | static bool[] bb = [1,0,1,1,0]; 728 | 729 | BitArray a; a.init(ba); 730 | BitArray b; b.init(bb); 731 | 732 | a |= b; 733 | assert(a[0] == 1); 734 | assert(a[1] == 0); 735 | assert(a[2] == 1); 736 | assert(a[3] == 1); 737 | assert(a[4] == 1); 738 | } 739 | 740 | /*************************************** 741 | * Support for operator ^= for bit arrays. 742 | */ 743 | BitArray opOpAssign(string op : "^")(BitArray e2) 744 | in 745 | { 746 | assert(len == e2.length); 747 | } 748 | do 749 | { 750 | auto dim = this.dim(); 751 | 752 | for (size_t i = 0; i < dim; i++) 753 | ptr[i] ^= e2.ptr[i]; 754 | return this; 755 | } 756 | 757 | unittest 758 | { 759 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 760 | 761 | static bool[] ba = [1,0,1,0,1]; 762 | static bool[] bb = [1,0,1,1,0]; 763 | 764 | BitArray a; a.init(ba); 765 | BitArray b; b.init(bb); 766 | 767 | a ^= b; 768 | assert(a[0] == 0); 769 | assert(a[1] == 0); 770 | assert(a[2] == 0); 771 | assert(a[3] == 1); 772 | assert(a[4] == 1); 773 | } 774 | 775 | /*************************************** 776 | * Support for operator -= for bit arrays. 777 | * 778 | * $(I a -= b) for BitArrays means the same thing as $(I a &= ~b). 779 | */ 780 | BitArray opOpAssign(string op : "-")(BitArray e2) 781 | in 782 | { 783 | assert(len == e2.length); 784 | } 785 | do 786 | { 787 | auto dim = this.dim(); 788 | 789 | for (size_t i = 0; i < dim; i++) 790 | ptr[i] &= ~e2.ptr[i]; 791 | return this; 792 | } 793 | 794 | unittest 795 | { 796 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 797 | 798 | static bool[] ba = [1,0,1,0,1]; 799 | static bool[] bb = [1,0,1,1,0]; 800 | 801 | BitArray a; a.init(ba); 802 | BitArray b; b.init(bb); 803 | 804 | a -= b; 805 | assert(a[0] == 0); 806 | assert(a[1] == 0); 807 | assert(a[2] == 0); 808 | assert(a[3] == 0); 809 | assert(a[4] == 1); 810 | } 811 | 812 | /*************************************** 813 | * Support for operator ~= for bit arrays. 814 | */ 815 | 816 | BitArray opOpAssign(string op : "~")(bool b) 817 | { 818 | length = len + 1; 819 | (this)[len - 1] = b; 820 | return this; 821 | } 822 | 823 | unittest 824 | { 825 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 826 | 827 | static bool[] ba = [1,0,1,0,1]; 828 | 829 | BitArray a; a.init(ba); 830 | BitArray b; 831 | 832 | b = (a ~= true); 833 | assert(a[0] == 1); 834 | assert(a[1] == 0); 835 | assert(a[2] == 1); 836 | assert(a[3] == 0); 837 | assert(a[4] == 1); 838 | assert(a[5] == 1); 839 | 840 | assert(b == a); 841 | } 842 | 843 | /*************************************** 844 | * ditto 845 | */ 846 | 847 | BitArray opOpAssign(string op : "~")(BitArray b) 848 | { 849 | auto istart = len; 850 | length = len + b.length; 851 | for (auto i = istart; i < len; i++) 852 | (this)[i] = b[i - istart]; 853 | return this; 854 | } 855 | 856 | unittest 857 | { 858 | debug(bitarray) printf("BitArray.opOpAssign unittest\n"); 859 | 860 | static bool[] ba = [1,0]; 861 | static bool[] bb = [0,1,0]; 862 | 863 | BitArray a; a.init(ba); 864 | BitArray b; b.init(bb); 865 | BitArray c; 866 | 867 | c = (a ~= b); 868 | assert(a.length == 5); 869 | assert(a[0] == 1); 870 | assert(a[1] == 0); 871 | assert(a[2] == 0); 872 | assert(a[3] == 1); 873 | assert(a[4] == 0); 874 | 875 | assert(c == a); 876 | } 877 | 878 | /*************************************** 879 | * Support for binary operator ~ for bit arrays. 880 | */ 881 | BitArray opBinary(string op : "~")(bool b) 882 | { 883 | auto r = this.dup; 884 | r.length = len + 1; 885 | r[len] = b; 886 | return r; 887 | } 888 | 889 | /** ditto */ 890 | BitArray opBinaryRight(string op : "~")(bool b) 891 | { 892 | BitArray r; 893 | 894 | r.length = len + 1; 895 | r[0] = b; 896 | for (size_t i = 0; i < len; i++) 897 | r[1 + i] = (this)[i]; 898 | return r; 899 | } 900 | 901 | /** ditto */ 902 | BitArray opBinary(string op : "~")(BitArray b) 903 | { 904 | BitArray r; 905 | 906 | r = this.dup(); 907 | r ~= b; 908 | return r; 909 | } 910 | 911 | unittest 912 | { 913 | debug(bitarray) printf("BitArray.opBinary unittest\n"); 914 | 915 | static bool[] ba = [1,0]; 916 | static bool[] bb = [0,1,0]; 917 | 918 | BitArray a; a.init(ba); 919 | BitArray b; b.init(bb); 920 | BitArray c; 921 | 922 | c = (a ~ b); 923 | assert(c.length == 5); 924 | assert(c[0] == 1); 925 | assert(c[1] == 0); 926 | assert(c[2] == 0); 927 | assert(c[3] == 1); 928 | assert(c[4] == 0); 929 | 930 | c = (a ~ true); 931 | assert(c.length == 3); 932 | assert(c[0] == 1); 933 | assert(c[1] == 0); 934 | assert(c[2] == 1); 935 | 936 | c = (false ~ a); 937 | assert(c.length == 3); 938 | assert(c[0] == 0); 939 | assert(c[1] == 1); 940 | assert(c[2] == 0); 941 | } 942 | } 943 | -------------------------------------------------------------------------------- /src/undead/cstream.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language. 2 | 3 | /** 4 | * $(RED Deprecated: This module is considered out-dated and not up to Phobos' 5 | * current standards.) 6 | * 7 | * The std.cstream module bridges core.stdc.stdio (or std.stdio) and std.stream. 8 | * Both core.stdc.stdio and std.stream are publicly imported by std.cstream. 9 | * 10 | * Macros: 11 | * WIKI=Phobos/StdCstream 12 | * 13 | * Copyright: Copyright Ben Hinkle 2007 - 2009. 14 | * License: $(WEB www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 15 | * Authors: Ben Hinkle 16 | * Source: $(PHOBOSSRC std/_cstream.d) 17 | */ 18 | /* Copyright Ben Hinkle 2007 - 2009. 19 | * Distributed under the Boost Software License, Version 1.0. 20 | * (See accompanying file LICENSE_1_0.txt or copy at 21 | * http://www.boost.org/LICENSE_1_0.txt) 22 | */ 23 | module undead.cstream; 24 | 25 | public import core.stdc.stdio; 26 | public import undead.stream; 27 | version(unittest) import std.stdio; 28 | 29 | import std.algorithm; 30 | 31 | /** 32 | * A Stream wrapper for a C file of type FILE*. 33 | */ 34 | class CFile : Stream { 35 | protected FILE* cfile; 36 | 37 | /** 38 | * Create the stream wrapper for the given C file. 39 | * Params: 40 | * cfile = a valid C $(B FILE) pointer to wrap. 41 | * mode = a bitwise combination of $(B FileMode.In) for a readable file 42 | * and $(B FileMode.Out) for a writeable file. 43 | * seekable = indicates if the stream should be _seekable. 44 | */ 45 | this(FILE* cfile, FileMode mode, bool seekable = false) { 46 | super(); 47 | this.file = cfile; 48 | readable = cast(bool)(mode & FileMode.In); 49 | writeable = cast(bool)(mode & FileMode.Out); 50 | this.seekable = seekable; 51 | } 52 | 53 | /** 54 | * Closes the stream. 55 | */ 56 | ~this() { close(); } 57 | 58 | /** 59 | * Property to get or set the underlying file for this stream. 60 | * Setting the file marks the stream as open. 61 | */ 62 | @property FILE* file() { return cfile; } 63 | 64 | /** 65 | * Ditto 66 | */ 67 | @property void file(FILE* cfile) { 68 | this.cfile = cfile; 69 | isopen = true; 70 | } 71 | 72 | /** 73 | * Overrides of the $(B Stream) methods to call the underlying $(B FILE*) 74 | * C functions. 75 | */ 76 | override void flush() { fflush(cfile); } 77 | 78 | /** 79 | * Ditto 80 | */ 81 | override void close() { 82 | if (isopen) 83 | fclose(cfile); 84 | isopen = readable = writeable = seekable = false; 85 | } 86 | 87 | /** 88 | * Ditto 89 | */ 90 | override bool eof() { 91 | return cast(bool)(readEOF || feof(cfile)); 92 | } 93 | 94 | /** 95 | * Ditto 96 | */ 97 | override char getc() { 98 | return cast(char)fgetc(cfile); 99 | } 100 | 101 | /** 102 | * Ditto 103 | */ 104 | override char ungetc(char c) { 105 | return cast(char)core.stdc.stdio.ungetc(c,cfile); 106 | } 107 | 108 | /** 109 | * Ditto 110 | */ 111 | override size_t readBlock(void* buffer, size_t size) { 112 | size_t n = fread(buffer,1,size,cfile); 113 | readEOF = cast(bool)(n == 0); 114 | return n; 115 | } 116 | 117 | /** 118 | * Ditto 119 | */ 120 | override size_t writeBlock(const void* buffer, size_t size) { 121 | return fwrite(buffer,1,size,cfile); 122 | } 123 | 124 | /** 125 | * Ditto 126 | */ 127 | override ulong seek(long offset, SeekPos rel) { 128 | readEOF = false; 129 | if (fseek(cfile,cast(int)offset,rel) != 0) 130 | throw new SeekException("unable to move file pointer"); 131 | return ftell(cfile); 132 | } 133 | 134 | /** 135 | * Ditto 136 | */ 137 | override void writeLine(const(char)[] s) { 138 | writeString(s); 139 | writeString("\n"); 140 | } 141 | 142 | /** 143 | * Ditto 144 | */ 145 | override void writeLineW(const(wchar)[] s) { 146 | writeStringW(s); 147 | writeStringW("\n"); 148 | } 149 | 150 | // run a few tests 151 | unittest { 152 | import undead.internal.file; 153 | import std.internal.cstring : tempCString; 154 | 155 | auto stream_file = (undead.internal.file.deleteme ~ "-stream.txt").tempCString(); 156 | FILE* f = fopen(stream_file,"w"); 157 | assert(f !is null); 158 | CFile file = new CFile(f,FileMode.Out); 159 | int i = 666; 160 | // should be ok to write 161 | assert(file.writeable); 162 | file.writeLine("Testing stream.d:"); 163 | file.writeString("Hello, world!"); 164 | file.write(i); 165 | // string#1 + string#2 + int should give exacly that 166 | version (Windows) 167 | assert(file.position == 19 + 13 + 4); 168 | version (Posix) 169 | assert(file.position == 18 + 13 + 4); 170 | file.close(); 171 | // no operations are allowed when file is closed 172 | assert(!file.readable && !file.writeable && !file.seekable); 173 | f = fopen(stream_file,"r"); 174 | file = new CFile(f,FileMode.In,true); 175 | // should be ok to read 176 | assert(file.readable); 177 | auto line = file.readLine(); 178 | auto exp = "Testing stream.d:"; 179 | assert(line[0] == 'T'); 180 | assert(line.length == exp.length); 181 | assert(!std.algorithm.cmp(line, "Testing stream.d:")); 182 | // jump over "Hello, " 183 | file.seek(7, SeekPos.Current); 184 | version (Windows) 185 | assert(file.position == 19 + 7); 186 | version (Posix) 187 | assert(file.position == 18 + 7); 188 | assert(!std.algorithm.cmp(file.readString(6), "world!")); 189 | i = 0; file.read(i); 190 | assert(i == 666); 191 | // string#1 + string#2 + int should give exacly that 192 | version (Windows) 193 | assert(file.position == 19 + 13 + 4); 194 | version (Posix) 195 | assert(file.position == 18 + 13 + 4); 196 | // we must be at the end of file 197 | file.close(); 198 | f = fopen(stream_file,"w+"); 199 | file = new CFile(f,FileMode.In|FileMode.Out,true); 200 | file.writeLine("Testing stream.d:"); 201 | file.writeLine("Another line"); 202 | file.writeLine(""); 203 | file.writeLine("That was blank"); 204 | file.position = 0; 205 | char[][] lines; 206 | foreach(char[] fileLine; file) { 207 | lines ~= fileLine.dup; 208 | } 209 | assert( lines.length == 5 ); 210 | assert( lines[0] == "Testing stream.d:"); 211 | assert( lines[1] == "Another line"); 212 | assert( lines[2] == ""); 213 | assert( lines[3] == "That was blank"); 214 | file.position = 0; 215 | lines = new char[][5]; 216 | foreach(ulong n, char[] fileLine; file) { 217 | lines[cast(size_t)(n-1)] = fileLine.dup; 218 | } 219 | assert( lines[0] == "Testing stream.d:"); 220 | assert( lines[1] == "Another line"); 221 | assert( lines[2] == ""); 222 | assert( lines[3] == "That was blank"); 223 | file.close(); 224 | remove(stream_file); 225 | } 226 | } 227 | 228 | /** 229 | * CFile wrapper of core.stdc.stdio.stdin (not seekable). 230 | */ 231 | __gshared CFile din; 232 | 233 | /** 234 | * CFile wrapper of core.stdc.stdio.stdout (not seekable). 235 | */ 236 | __gshared CFile dout; 237 | 238 | /** 239 | * CFile wrapper of core.stdc.stdio.stderr (not seekable). 240 | */ 241 | __gshared CFile derr; 242 | 243 | shared static this() { 244 | // open standard I/O devices 245 | din = new CFile(core.stdc.stdio.stdin,FileMode.In); 246 | dout = new CFile(core.stdc.stdio.stdout,FileMode.Out); 247 | derr = new CFile(core.stdc.stdio.stderr,FileMode.Out); 248 | } 249 | 250 | -------------------------------------------------------------------------------- /src/undead/datebase.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language. 2 | 3 | /** 4 | * The only purpose of this module is to do the static construction for 5 | * std.date, to eliminate cyclic construction errors. 6 | * 7 | * Copyright: Copyright Digital Mars 2000 - 2009. 8 | * License: Boost License 1.0. 9 | * Authors: $(WEB digitalmars.com, Walter Bright) 10 | * Source: $(PHOBOSSRC std/_datebase.d) 11 | */ 12 | /* 13 | * Copyright Digital Mars 2000 - 2009. 14 | * Distributed under the Boost Software License, Version 1.0. 15 | * (See accompanying file LICENSE_1_0.txt or copy at 16 | * http://www.boost.org/LICENSE_1_0.txt) 17 | */ 18 | module undead.datebase; 19 | 20 | extern(C) void std_date_static_this(); 21 | 22 | shared static this() 23 | { 24 | std_date_static_this(); 25 | } 26 | -------------------------------------------------------------------------------- /src/undead/dateparse.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language. 2 | 3 | /** 4 | * $(RED Deprecated. It will be removed in February 2012. 5 | * Please use std.datetime instead.) 6 | * 7 | * dateparse module. 8 | * 9 | * Copyright: Copyright Digital Mars 2000 - 2009. 10 | * License: Boost License 1.0. 11 | * Authors: $(WEB digitalmars.com, Walter Bright) 12 | * Source: $(PHOBOSSRC std/_dateparse.d) 13 | */ 14 | /* 15 | * Copyright Digital Mars 2000 - 2009. 16 | * Distributed under the Boost Software License, Version 1.0. 17 | * (See accompanying file LICENSE_1_0.txt or copy at 18 | * http://www.boost.org/LICENSE_1_0.txt) 19 | */ 20 | module undead.dateparse; 21 | 22 | private 23 | { 24 | import std.algorithm, std.string; 25 | import core.stdc.stdlib; 26 | import undead.date; 27 | } 28 | 29 | //deprecated: 30 | 31 | //debug=dateparse; 32 | 33 | class DateParseError : Error 34 | { 35 | this(string s) 36 | { 37 | super("Invalid date string: " ~ s); 38 | } 39 | } 40 | 41 | struct DateParse 42 | { 43 | void parse(string s, out Date date) 44 | { 45 | this = DateParse.init; 46 | 47 | //version (Win32) 48 | buffer = (cast(char *)alloca(s.length))[0 .. s.length]; 49 | //else 50 | //buffer = new char[s.length]; 51 | 52 | debug(dateparse) printf("DateParse.parse('%.*s')\n", s); 53 | if (!parseString(s)) 54 | { 55 | goto Lerror; 56 | } 57 | 58 | /+ 59 | if (year == year.init) 60 | year = 0; 61 | else 62 | +/ 63 | debug(dateparse) 64 | printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n", 65 | year, month, day, 66 | hours, minutes, seconds, ms, 67 | weekday, tzcorrection); 68 | if ( 69 | year == year.init || 70 | (month < 1 || month > 12) || 71 | (day < 1 || day > 31) || 72 | (hours < 0 || hours > 23) || 73 | (minutes < 0 || minutes > 59) || 74 | (seconds < 0 || seconds > 59) || 75 | (tzcorrection != int.min && 76 | ((tzcorrection < -2300 || tzcorrection > 2300) || 77 | (tzcorrection % 10))) 78 | ) 79 | { 80 | Lerror: 81 | throw new DateParseError(s); 82 | } 83 | 84 | if (ampm) 85 | { if (hours > 12) 86 | goto Lerror; 87 | if (hours < 12) 88 | { 89 | if (ampm == 2) // if P.M. 90 | hours += 12; 91 | } 92 | else if (ampm == 1) // if 12am 93 | { 94 | hours = 0; // which is midnight 95 | } 96 | } 97 | 98 | // if (tzcorrection != tzcorrection.init) 99 | // tzcorrection /= 100; 100 | 101 | if (year >= 0 && year <= 99) 102 | year += 1900; 103 | 104 | date.year = year; 105 | date.month = month; 106 | date.day = day; 107 | date.hour = hours; 108 | date.minute = minutes; 109 | date.second = seconds; 110 | date.ms = ms; 111 | date.weekday = weekday; 112 | date.tzcorrection = tzcorrection; 113 | } 114 | 115 | 116 | private: 117 | int year = int.min; // our "nan" Date value 118 | int month; // 1..12 119 | int day; // 1..31 120 | int hours; // 0..23 121 | int minutes; // 0..59 122 | int seconds; // 0..59 123 | int ms; // 0..999 124 | int weekday; // 1..7 125 | int ampm; // 0: not specified 126 | // 1: AM 127 | // 2: PM 128 | int tzcorrection = int.min; // -1200..1200 correction in hours 129 | 130 | string s; 131 | int si; 132 | int number; 133 | char[] buffer; 134 | 135 | enum DP : byte 136 | { 137 | err, 138 | weekday, 139 | month, 140 | number, 141 | end, 142 | colon, 143 | minus, 144 | slash, 145 | ampm, 146 | plus, 147 | tz, 148 | dst, 149 | dsttz, 150 | } 151 | 152 | DP nextToken() 153 | { int nest; 154 | uint c; 155 | int bi; 156 | DP result = DP.err; 157 | 158 | //printf("DateParse::nextToken()\n"); 159 | for (;;) 160 | { 161 | assert(si <= s.length); 162 | if (si == s.length) 163 | { result = DP.end; 164 | goto Lret; 165 | } 166 | //printf("\ts[%d] = '%c'\n", si, s[si]); 167 | switch (s[si]) 168 | { 169 | case ':': result = DP.colon; goto ret_inc; 170 | case '+': result = DP.plus; goto ret_inc; 171 | case '-': result = DP.minus; goto ret_inc; 172 | case '/': result = DP.slash; goto ret_inc; 173 | case '.': 174 | version(DATE_DOT_DELIM) 175 | { 176 | result = DP.slash; 177 | goto ret_inc; 178 | } 179 | else 180 | { 181 | si++; 182 | break; 183 | } 184 | 185 | ret_inc: 186 | si++; 187 | goto Lret; 188 | 189 | case ' ': 190 | case '\n': 191 | case '\r': 192 | case '\t': 193 | case ',': 194 | si++; 195 | break; 196 | 197 | case '(': // comment 198 | nest = 1; 199 | for (;;) 200 | { 201 | si++; 202 | if (si == s.length) 203 | goto Lret; // error 204 | switch (s[si]) 205 | { 206 | case '(': 207 | nest++; 208 | break; 209 | 210 | case ')': 211 | if (--nest == 0) 212 | goto Lendofcomment; 213 | break; 214 | 215 | default: 216 | break; 217 | } 218 | } 219 | Lendofcomment: 220 | si++; 221 | break; 222 | 223 | default: 224 | number = 0; 225 | for (;;) 226 | { 227 | if (si == s.length) 228 | // c cannot be undefined here 229 | break; 230 | c = s[si]; 231 | if (!(c >= '0' && c <= '9')) 232 | break; 233 | result = DP.number; 234 | number = number * 10 + (c - '0'); 235 | si++; 236 | } 237 | if (result == DP.number) 238 | goto Lret; 239 | 240 | bi = 0; 241 | bufloop: 242 | while (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') 243 | { 244 | if (c < 'a') // if upper case 245 | c += cast(uint)'a' - cast(uint)'A'; // to lower case 246 | buffer[bi] = cast(char)c; 247 | bi++; 248 | do 249 | { 250 | si++; 251 | if (si == s.length) 252 | break bufloop; 253 | c = s[si]; 254 | } while (c == '.'); // ignore embedded '.'s 255 | } 256 | result = classify(buffer[0 .. bi].idup); 257 | goto Lret; 258 | } 259 | } 260 | Lret: 261 | //printf("-DateParse::nextToken()\n"); 262 | return result; 263 | } 264 | 265 | DP classify(string buf) 266 | { 267 | struct DateID 268 | { 269 | string name; 270 | DP tok; 271 | short value; 272 | } 273 | 274 | static immutable DateID[] dateidtab = 275 | [ 276 | { "january", DP.month, 1}, 277 | { "february", DP.month, 2}, 278 | { "march", DP.month, 3}, 279 | { "april", DP.month, 4}, 280 | { "may", DP.month, 5}, 281 | { "june", DP.month, 6}, 282 | { "july", DP.month, 7}, 283 | { "august", DP.month, 8}, 284 | { "september", DP.month, 9}, 285 | { "october", DP.month, 10}, 286 | { "november", DP.month, 11}, 287 | { "december", DP.month, 12}, 288 | { "jan", DP.month, 1}, 289 | { "feb", DP.month, 2}, 290 | { "mar", DP.month, 3}, 291 | { "apr", DP.month, 4}, 292 | { "jun", DP.month, 6}, 293 | { "jul", DP.month, 7}, 294 | { "aug", DP.month, 8}, 295 | { "sep", DP.month, 9}, 296 | { "sept", DP.month, 9}, 297 | { "oct", DP.month, 10}, 298 | { "nov", DP.month, 11}, 299 | { "dec", DP.month, 12}, 300 | 301 | { "sunday", DP.weekday, 1}, 302 | { "monday", DP.weekday, 2}, 303 | { "tuesday", DP.weekday, 3}, 304 | { "tues", DP.weekday, 3}, 305 | { "wednesday", DP.weekday, 4}, 306 | { "wednes", DP.weekday, 4}, 307 | { "thursday", DP.weekday, 5}, 308 | { "thur", DP.weekday, 5}, 309 | { "thurs", DP.weekday, 5}, 310 | { "friday", DP.weekday, 6}, 311 | { "saturday", DP.weekday, 7}, 312 | 313 | { "sun", DP.weekday, 1}, 314 | { "mon", DP.weekday, 2}, 315 | { "tue", DP.weekday, 3}, 316 | { "wed", DP.weekday, 4}, 317 | { "thu", DP.weekday, 5}, 318 | { "fri", DP.weekday, 6}, 319 | { "sat", DP.weekday, 7}, 320 | 321 | { "am", DP.ampm, 1}, 322 | { "pm", DP.ampm, 2}, 323 | 324 | { "gmt", DP.tz, +000}, 325 | { "ut", DP.tz, +000}, 326 | { "utc", DP.tz, +000}, 327 | { "wet", DP.tz, +000}, 328 | { "z", DP.tz, +000}, 329 | { "wat", DP.tz, +100}, 330 | { "a", DP.tz, +100}, 331 | { "at", DP.tz, +200}, 332 | { "b", DP.tz, +200}, 333 | { "c", DP.tz, +300}, 334 | { "ast", DP.tz, +400}, 335 | { "d", DP.tz, +400}, 336 | { "est", DP.tz, +500}, 337 | { "e", DP.tz, +500}, 338 | { "cst", DP.tz, +600}, 339 | { "f", DP.tz, +600}, 340 | { "mst", DP.tz, +700}, 341 | { "g", DP.tz, +700}, 342 | { "pst", DP.tz, +800}, 343 | { "h", DP.tz, +800}, 344 | { "yst", DP.tz, +900}, 345 | { "i", DP.tz, +900}, 346 | { "ahst", DP.tz, +1000}, 347 | { "cat", DP.tz, +1000}, 348 | { "hst", DP.tz, +1000}, 349 | { "k", DP.tz, +1000}, 350 | { "nt", DP.tz, +1100}, 351 | { "l", DP.tz, +1100}, 352 | { "idlw", DP.tz, +1200}, 353 | { "m", DP.tz, +1200}, 354 | 355 | { "cet", DP.tz, -100}, 356 | { "fwt", DP.tz, -100}, 357 | { "met", DP.tz, -100}, 358 | { "mewt", DP.tz, -100}, 359 | { "swt", DP.tz, -100}, 360 | { "n", DP.tz, -100}, 361 | { "eet", DP.tz, -200}, 362 | { "o", DP.tz, -200}, 363 | { "bt", DP.tz, -300}, 364 | { "p", DP.tz, -300}, 365 | { "zp4", DP.tz, -400}, 366 | { "q", DP.tz, -400}, 367 | { "zp5", DP.tz, -500}, 368 | { "r", DP.tz, -500}, 369 | { "zp6", DP.tz, -600}, 370 | { "s", DP.tz, -600}, 371 | { "wast", DP.tz, -700}, 372 | { "t", DP.tz, -700}, 373 | { "cct", DP.tz, -800}, 374 | { "u", DP.tz, -800}, 375 | { "jst", DP.tz, -900}, 376 | { "v", DP.tz, -900}, 377 | { "east", DP.tz, -1000}, 378 | { "gst", DP.tz, -1000}, 379 | { "w", DP.tz, -1000}, 380 | { "x", DP.tz, -1100}, 381 | { "idle", DP.tz, -1200}, 382 | { "nzst", DP.tz, -1200}, 383 | { "nzt", DP.tz, -1200}, 384 | { "y", DP.tz, -1200}, 385 | 386 | { "bst", DP.dsttz, 000}, 387 | { "adt", DP.dsttz, +400}, 388 | { "edt", DP.dsttz, +500}, 389 | { "cdt", DP.dsttz, +600}, 390 | { "mdt", DP.dsttz, +700}, 391 | { "pdt", DP.dsttz, +800}, 392 | { "ydt", DP.dsttz, +900}, 393 | { "hdt", DP.dsttz, +1000}, 394 | { "mest", DP.dsttz, -100}, 395 | { "mesz", DP.dsttz, -100}, 396 | { "sst", DP.dsttz, -100}, 397 | { "fst", DP.dsttz, -100}, 398 | { "wadt", DP.dsttz, -700}, 399 | { "eadt", DP.dsttz, -1000}, 400 | { "nzdt", DP.dsttz, -1200}, 401 | 402 | { "dst", DP.dst, 0}, 403 | ]; 404 | 405 | //message(DTEXT("DateParse::classify('%s')\n"), buf); 406 | 407 | // Do a linear search. Yes, it would be faster with a binary 408 | // one. 409 | for (uint i = 0; i < dateidtab.length; i++) 410 | { 411 | if (cmp(dateidtab[i].name, buf) == 0) 412 | { 413 | number = dateidtab[i].value; 414 | return dateidtab[i].tok; 415 | } 416 | } 417 | return DP.err; 418 | } 419 | 420 | int parseString(string s) 421 | { 422 | int n1; 423 | int dp; 424 | int sisave; 425 | int result; 426 | 427 | //message(DTEXT("DateParse::parseString('%ls')\n"), s); 428 | this.s = s; 429 | si = 0; 430 | dp = nextToken(); 431 | for (;;) 432 | { 433 | //message(DTEXT("\tdp = %d\n"), dp); 434 | switch (dp) 435 | { 436 | case DP.end: 437 | result = 1; 438 | Lret: 439 | return result; 440 | 441 | case DP.err: 442 | case_error: 443 | //message(DTEXT("\terror\n")); 444 | default: 445 | result = 0; 446 | goto Lret; 447 | 448 | case DP.minus: 449 | break; // ignore spurious '-' 450 | 451 | case DP.weekday: 452 | weekday = number; 453 | break; 454 | 455 | case DP.month: // month day, [year] 456 | month = number; 457 | dp = nextToken(); 458 | if (dp == DP.number) 459 | { 460 | day = number; 461 | sisave = si; 462 | dp = nextToken(); 463 | if (dp == DP.number) 464 | { 465 | n1 = number; 466 | dp = nextToken(); 467 | if (dp == DP.colon) 468 | { // back up, not a year 469 | si = sisave; 470 | } 471 | else 472 | { year = n1; 473 | continue; 474 | } 475 | break; 476 | } 477 | } 478 | continue; 479 | 480 | case DP.number: 481 | n1 = number; 482 | dp = nextToken(); 483 | switch (dp) 484 | { 485 | case DP.end: 486 | year = n1; 487 | break; 488 | 489 | case DP.minus: 490 | case DP.slash: // n1/ ? ? ? 491 | dp = parseCalendarDate(n1); 492 | if (dp == DP.err) 493 | goto case_error; 494 | break; 495 | 496 | case DP.colon: // hh:mm [:ss] [am | pm] 497 | dp = parseTimeOfDay(n1); 498 | if (dp == DP.err) 499 | goto case_error; 500 | break; 501 | 502 | case DP.ampm: 503 | hours = n1; 504 | minutes = 0; 505 | seconds = 0; 506 | ampm = number; 507 | break; 508 | 509 | case DP.month: 510 | day = n1; 511 | month = number; 512 | dp = nextToken(); 513 | if (dp == DP.number) 514 | { // day month year 515 | year = number; 516 | dp = nextToken(); 517 | } 518 | break; 519 | 520 | default: 521 | year = n1; 522 | break; 523 | } 524 | continue; 525 | } 526 | dp = nextToken(); 527 | } 528 | // @@@ bug in the compiler: this is never reachable 529 | assert(0); 530 | } 531 | 532 | int parseCalendarDate(int n1) 533 | { 534 | int n2; 535 | int n3; 536 | int dp; 537 | 538 | debug(dateparse) printf("DateParse.parseCalendarDate(%d)\n", n1); 539 | dp = nextToken(); 540 | if (dp == DP.month) // day/month 541 | { 542 | day = n1; 543 | month = number; 544 | dp = nextToken(); 545 | if (dp == DP.number) 546 | { // day/month year 547 | year = number; 548 | dp = nextToken(); 549 | } 550 | else if (dp == DP.minus || dp == DP.slash) 551 | { // day/month/year 552 | dp = nextToken(); 553 | if (dp != DP.number) 554 | goto case_error; 555 | year = number; 556 | dp = nextToken(); 557 | } 558 | return dp; 559 | } 560 | if (dp != DP.number) 561 | goto case_error; 562 | n2 = number; 563 | //message(DTEXT("\tn2 = %d\n"), n2); 564 | dp = nextToken(); 565 | if (dp == DP.minus || dp == DP.slash) 566 | { 567 | dp = nextToken(); 568 | if (dp != DP.number) 569 | goto case_error; 570 | n3 = number; 571 | //message(DTEXT("\tn3 = %d\n"), n3); 572 | dp = nextToken(); 573 | 574 | // case1: year/month/day 575 | // case2: month/day/year 576 | int case1, case2; 577 | 578 | case1 = (n1 > 12 || 579 | (n2 >= 1 && n2 <= 12) && 580 | (n3 >= 1 && n3 <= 31)); 581 | case2 = ((n1 >= 1 && n1 <= 12) && 582 | (n2 >= 1 && n2 <= 31) || 583 | n3 > 31); 584 | if (case1 == case2) 585 | goto case_error; 586 | if (case1) 587 | { 588 | year = n1; 589 | month = n2; 590 | day = n3; 591 | } 592 | else 593 | { 594 | month = n1; 595 | day = n2; 596 | year = n3; 597 | } 598 | } 599 | else 600 | { // must be month/day 601 | month = n1; 602 | day = n2; 603 | } 604 | return dp; 605 | 606 | case_error: 607 | return DP.err; 608 | } 609 | 610 | int parseTimeOfDay(int n1) 611 | { 612 | int dp; 613 | int sign; 614 | 615 | // 12am is midnight 616 | // 12pm is noon 617 | 618 | //message(DTEXT("DateParse::parseTimeOfDay(%d)\n"), n1); 619 | hours = n1; 620 | dp = nextToken(); 621 | if (dp != DP.number) 622 | goto case_error; 623 | minutes = number; 624 | dp = nextToken(); 625 | if (dp == DP.colon) 626 | { 627 | dp = nextToken(); 628 | if (dp != DP.number) 629 | goto case_error; 630 | seconds = number; 631 | dp = nextToken(); 632 | } 633 | else 634 | seconds = 0; 635 | 636 | if (dp == DP.ampm) 637 | { 638 | ampm = number; 639 | dp = nextToken(); 640 | } 641 | else if (dp == DP.plus || dp == DP.minus) 642 | { 643 | Loffset: 644 | sign = (dp == DP.minus) ? -1 : 1; 645 | dp = nextToken(); 646 | if (dp != DP.number) 647 | goto case_error; 648 | tzcorrection = -sign * number; 649 | dp = nextToken(); 650 | } 651 | else if (dp == DP.tz) 652 | { 653 | tzcorrection = number; 654 | dp = nextToken(); 655 | if (number == 0 && (dp == DP.plus || dp == DP.minus)) 656 | goto Loffset; 657 | if (dp == DP.dst) 658 | { tzcorrection += 100; 659 | dp = nextToken(); 660 | } 661 | } 662 | else if (dp == DP.dsttz) 663 | { 664 | tzcorrection = number; 665 | dp = nextToken(); 666 | } 667 | 668 | return dp; 669 | 670 | case_error: 671 | return DP.err; 672 | } 673 | 674 | } 675 | 676 | unittest 677 | { 678 | DateParse dp; 679 | Date d; 680 | 681 | dp.parse("March 10, 1959 12:00 -800", d); 682 | assert(d.year == 1959); 683 | assert(d.month == 3); 684 | assert(d.day == 10); 685 | assert(d.hour == 12); 686 | assert(d.minute == 0); 687 | assert(d.second == 0); 688 | assert(d.ms == 0); 689 | assert(d.weekday == 0); 690 | assert(d.tzcorrection == 800); 691 | 692 | dp.parse("Tue Apr 02 02:04:57 GMT-0800 1996", d); 693 | assert(d.year == 1996); 694 | assert(d.month == 4); 695 | assert(d.day == 2); 696 | assert(d.hour == 2); 697 | assert(d.minute == 4); 698 | assert(d.second == 57); 699 | assert(d.ms == 0); 700 | assert(d.weekday == 3); 701 | assert(d.tzcorrection == 800); 702 | 703 | dp.parse("March 14, -1980 21:14:50", d); 704 | assert(d.year == 1980); 705 | assert(d.month == 3); 706 | assert(d.day == 14); 707 | assert(d.hour == 21); 708 | assert(d.minute == 14); 709 | assert(d.second == 50); 710 | assert(d.ms == 0); 711 | assert(d.weekday == 0); 712 | assert(d.tzcorrection == int.min); 713 | 714 | dp.parse("Tue Apr 02 02:04:57 1996", d); 715 | assert(d.year == 1996); 716 | assert(d.month == 4); 717 | assert(d.day == 2); 718 | assert(d.hour == 2); 719 | assert(d.minute == 4); 720 | assert(d.second == 57); 721 | assert(d.ms == 0); 722 | assert(d.weekday == 3); 723 | assert(d.tzcorrection == int.min); 724 | 725 | dp.parse("Tue, 02 Apr 1996 02:04:57 G.M.T.", d); 726 | assert(d.year == 1996); 727 | assert(d.month == 4); 728 | assert(d.day == 2); 729 | assert(d.hour == 2); 730 | assert(d.minute == 4); 731 | assert(d.second == 57); 732 | assert(d.ms == 0); 733 | assert(d.weekday == 3); 734 | assert(d.tzcorrection == 0); 735 | 736 | dp.parse("December 31, 3000", d); 737 | assert(d.year == 3000); 738 | assert(d.month == 12); 739 | assert(d.day == 31); 740 | assert(d.hour == 0); 741 | assert(d.minute == 0); 742 | assert(d.second == 0); 743 | assert(d.ms == 0); 744 | assert(d.weekday == 0); 745 | assert(d.tzcorrection == int.min); 746 | 747 | dp.parse("Wed, 31 Dec 1969 16:00:00 GMT", d); 748 | assert(d.year == 1969); 749 | assert(d.month == 12); 750 | assert(d.day == 31); 751 | assert(d.hour == 16); 752 | assert(d.minute == 0); 753 | assert(d.second == 0); 754 | assert(d.ms == 0); 755 | assert(d.weekday == 4); 756 | assert(d.tzcorrection == 0); 757 | 758 | dp.parse("1/1/1999 12:30 AM", d); 759 | assert(d.year == 1999); 760 | assert(d.month == 1); 761 | assert(d.day == 1); 762 | assert(d.hour == 0); 763 | assert(d.minute == 30); 764 | assert(d.second == 0); 765 | assert(d.ms == 0); 766 | assert(d.weekday == 0); 767 | assert(d.tzcorrection == int.min); 768 | 769 | dp.parse("Tue, 20 May 2003 15:38:58 +0530", d); 770 | assert(d.year == 2003); 771 | assert(d.month == 5); 772 | assert(d.day == 20); 773 | assert(d.hour == 15); 774 | assert(d.minute == 38); 775 | assert(d.second == 58); 776 | assert(d.ms == 0); 777 | assert(d.weekday == 3); 778 | assert(d.tzcorrection == -530); 779 | 780 | debug(dateparse) printf("year = %d, month = %d, day = %d\n%02d:%02d:%02d.%03d\nweekday = %d, tzcorrection = %d\n", 781 | d.year, d.month, d.day, 782 | d.hour, d.minute, d.second, d.ms, 783 | d.weekday, d.tzcorrection); 784 | } 785 | -------------------------------------------------------------------------------- /src/undead/internal/file.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language 2 | 3 | module undead.internal.file; 4 | 5 | // Copied from std.file. undead doesn't have access to it, but some modules 6 | // in undead used std.file.deleteme when they were in Phobos, so this gives 7 | // them access to a version of it. 8 | public @property string deleteme() @safe 9 | { 10 | import std.conv : to; 11 | import std.file : tempDir; 12 | import std.path : buildPath; 13 | import std.process : thisProcessID; 14 | static _deleteme = "deleteme.dmd.unittest.pid"; 15 | static _first = true; 16 | 17 | if(_first) 18 | { 19 | _deleteme = buildPath(tempDir(), _deleteme) ~ to!string(thisProcessID); 20 | _first = false; 21 | } 22 | 23 | return _deleteme; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/undead/metastrings.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language. 2 | 3 | /** 4 | Templates with which to do compile-time manipulation of strings. 5 | 6 | Macros: 7 | WIKI = Phobos/StdMetastrings 8 | 9 | Copyright: Copyright Digital Mars 2007 - 2009. 10 | License: Boost License 1.0. 11 | Authors: $(WEB digitalmars.com, Walter Bright), 12 | Don Clugston 13 | Source: $(PHOBOSSRC std/_metastrings.d) 14 | */ 15 | /* 16 | Copyright Digital Mars 2007 - 2009. 17 | Distributed under the Boost Software License, Version 1.0. 18 | (See accompanying file LICENSE_1_0.txt or copy at 19 | http://www.boost.org/LICENSE_1_0.txt) 20 | */ 21 | module undead.metastrings; 22 | 23 | /** 24 | Formats constants into a string at compile time. Analogous to $(XREF 25 | string,format). 26 | 27 | Parameters: 28 | 29 | A = tuple of constants, which can be strings, characters, or integral 30 | values. 31 | 32 | Formats: 33 | * The formats supported are %s for strings, and %% 34 | * for the % character. 35 | Example: 36 | --- 37 | import std.metastrings; 38 | import std.stdio; 39 | 40 | void main() 41 | { 42 | string s = Format!("Arg %s = %s", "foo", 27); 43 | writefln(s); // "Arg foo = 27" 44 | } 45 | * --- 46 | */ 47 | 48 | template Format(A...) 49 | { 50 | static if (A.length == 0) 51 | enum Format = ""; 52 | else static if (is(typeof(A[0]) : const(char)[])) 53 | enum Format = FormatString!(A[0], A[1..$]); 54 | else 55 | enum Format = toStringNow!(A[0]) ~ Format!(A[1..$]); 56 | } 57 | 58 | template FormatString(const(char)[] F, A...) 59 | { 60 | static if (F.length == 0) 61 | enum FormatString = Format!(A); 62 | else static if (F.length == 1) 63 | enum FormatString = F[0] ~ Format!(A); 64 | else static if (F[0..2] == "%s") 65 | enum FormatString 66 | = toStringNow!(A[0]) ~ FormatString!(F[2..$],A[1..$]); 67 | else static if (F[0..2] == "%%") 68 | enum FormatString = "%" ~ FormatString!(F[2..$],A); 69 | else 70 | { 71 | static assert(F[0] != '%', "unrecognized format %" ~ F[1]); 72 | enum FormatString = F[0] ~ FormatString!(F[1..$],A); 73 | } 74 | } 75 | 76 | unittest 77 | { 78 | auto s = Format!("hel%slo", "world", -138, 'c', true); 79 | assert(s == "helworldlo-138ctrue", "[" ~ s ~ "]"); 80 | } 81 | 82 | /** 83 | * Convert constant argument to a string. 84 | */ 85 | 86 | template toStringNow(ulong v) 87 | { 88 | static if (v < 10) 89 | enum toStringNow = "" ~ cast(char)(v + '0'); 90 | else 91 | enum toStringNow = toStringNow!(v / 10) ~ toStringNow!(v % 10); 92 | } 93 | 94 | unittest 95 | { 96 | static assert(toStringNow!(1uL << 62) == "4611686018427387904"); 97 | } 98 | 99 | /// ditto 100 | template toStringNow(long v) 101 | { 102 | static if (v < 0) 103 | enum toStringNow = "-" ~ toStringNow!(cast(ulong) -v); 104 | else 105 | enum toStringNow = toStringNow!(cast(ulong) v); 106 | } 107 | 108 | unittest 109 | { 110 | static assert(toStringNow!(0x100000000) == "4294967296"); 111 | static assert(toStringNow!(-138L) == "-138"); 112 | } 113 | 114 | /// ditto 115 | template toStringNow(uint U) 116 | { 117 | enum toStringNow = toStringNow!(cast(ulong)U); 118 | } 119 | 120 | /// ditto 121 | template toStringNow(int I) 122 | { 123 | enum toStringNow = toStringNow!(cast(long)I); 124 | } 125 | 126 | /// ditto 127 | template toStringNow(bool B) 128 | { 129 | enum toStringNow = B ? "true" : "false"; 130 | } 131 | 132 | /// ditto 133 | template toStringNow(string S) 134 | { 135 | enum toStringNow = S; 136 | } 137 | 138 | /// ditto 139 | template toStringNow(char C) 140 | { 141 | enum toStringNow = "" ~ C; 142 | } 143 | 144 | 145 | /******** 146 | * Parse unsigned integer literal from the start of string s. 147 | * returns: 148 | * .value = the integer literal as a string, 149 | * .rest = the string following the integer literal 150 | * Otherwise: 151 | * .value = null, 152 | * .rest = s 153 | */ 154 | 155 | template parseUinteger(const(char)[] s) 156 | { 157 | static if (s.length == 0) 158 | { 159 | enum value = ""; 160 | enum rest = ""; 161 | } 162 | else static if (s[0] >= '0' && s[0] <= '9') 163 | { 164 | enum value = s[0] ~ parseUinteger!(s[1..$]).value; 165 | enum rest = parseUinteger!(s[1..$]).rest; 166 | } 167 | else 168 | { 169 | enum value = ""; 170 | enum rest = s; 171 | } 172 | } 173 | 174 | /******** 175 | Parse integer literal optionally preceded by $(D '-') from the start 176 | of string $(D s). 177 | 178 | Returns: 179 | .value = the integer literal as a string, 180 | .rest = the string following the integer literal 181 | 182 | Otherwise: 183 | .value = null, 184 | .rest = s 185 | */ 186 | 187 | template parseInteger(const(char)[] s) 188 | { 189 | static if (s.length == 0) 190 | { 191 | enum value = ""; 192 | enum rest = ""; 193 | } 194 | else static if (s[0] >= '0' && s[0] <= '9') 195 | { 196 | enum value = s[0] ~ parseUinteger!(s[1..$]).value; 197 | enum rest = parseUinteger!(s[1..$]).rest; 198 | } 199 | else static if (s.length >= 2 && 200 | s[0] == '-' && s[1] >= '0' && s[1] <= '9') 201 | { 202 | enum value = s[0..2] ~ parseUinteger!(s[2..$]).value; 203 | enum rest = parseUinteger!(s[2..$]).rest; 204 | } 205 | else 206 | { 207 | enum value = ""; 208 | enum rest = s; 209 | } 210 | } 211 | 212 | unittest 213 | { 214 | assert(parseUinteger!("1234abc").value == "1234"); 215 | assert(parseUinteger!("1234abc").rest == "abc"); 216 | assert(parseInteger!("-1234abc").value == "-1234"); 217 | assert(parseInteger!("-1234abc").rest == "abc"); 218 | } 219 | -------------------------------------------------------------------------------- /src/undead/signals.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language. 2 | 3 | /** 4 | * Signals and Slots are an implementation of the Observer Pattern. 5 | * Essentially, when a Signal is emitted, a list of connected Observers 6 | * (called slots) are called. 7 | * 8 | * There have been several D implementations of Signals and Slots. 9 | * This version makes use of several new features in D, which make 10 | * using it simpler and less error prone. In particular, it is no 11 | * longer necessary to instrument the slots. 12 | * 13 | * References: 14 | * $(LUCKY A Deeper Look at Signals and Slots)$(BR) 15 | * $(LINK2 http://en.wikipedia.org/wiki/Observer_pattern, Observer pattern)$(BR) 16 | * $(LINK2 http://en.wikipedia.org/wiki/Signals_and_slots, Wikipedia)$(BR) 17 | * $(LINK2 http://boost.org/doc/html/$(SIGNALS).html, Boost Signals)$(BR) 18 | * $(LINK2 http://qt-project.org/doc/qt-5/signalsandslots.html, Qt)$(BR) 19 | * 20 | * There has been a great deal of discussion in the D newsgroups 21 | * over this, and several implementations: 22 | * 23 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/signal_slots_library_4825.html, signal slots library)$(BR) 24 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Signals_and_Slots_in_D_42387.html, Signals and Slots in D)$(BR) 25 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dynamic_binding_--_Qt_s_Signals_and_Slots_vs_Objective-C_42260.html, Dynamic binding -- Qt's Signals and Slots vs Objective-C)$(BR) 26 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Dissecting_the_SS_42377.html, Dissecting the SS)$(BR) 27 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/dwt/about_harmonia_454.html, about harmonia)$(BR) 28 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/announce/1502.html, Another event handling module)$(BR) 29 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/41825.html, Suggestion: signal/slot mechanism)$(BR) 30 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/13251.html, Signals and slots?)$(BR) 31 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/10714.html, Signals and slots ready for evaluation)$(BR) 32 | * $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/1393.html, Signals & Slots for Walter)$(BR) 33 | * $(LINK2 http://www.digitalmars.com/d/archives/28456.html, Signal/Slot mechanism?)$(BR) 34 | * $(LINK2 http://www.digitalmars.com/d/archives/19470.html, Modern Features?)$(BR) 35 | * $(LINK2 http://www.digitalmars.com/d/archives/16592.html, Delegates vs interfaces)$(BR) 36 | * $(LINK2 http://www.digitalmars.com/d/archives/16583.html, The importance of component programming (properties$(COMMA) signals and slots$(COMMA) etc))$(BR) 37 | * $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR) 38 | * 39 | * Bugs: 40 | * $(RED Slots can only be delegates formed from class objects or 41 | * interfaces to class objects. If a delegate to something else 42 | * is passed to connect(), such as a struct member function, 43 | * a nested function, a COM interface or a closure, undefined behavior 44 | * will result.) 45 | * 46 | * Not safe for multiple threads operating on the same signals 47 | * or slots. 48 | * Macros: 49 | * SIGNALS=signals 50 | * 51 | * Copyright: Copyright The D Language Foundation 2000 - 2009. 52 | * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 53 | * Authors: $(HTTP digitalmars.com, Walter Bright) 54 | * Source: $(PHOBOSSRC std/signals.d) 55 | * 56 | * $(SCRIPT inhibitQuickIndex = 1;) 57 | */ 58 | /* Copyright The D Language Foundation 2000 - 2009. 59 | * Distributed under the Boost Software License, Version 1.0. 60 | * (See accompanying file LICENSE_1_0.txt or copy at 61 | * http://www.boost.org/LICENSE_1_0.txt) 62 | */ 63 | module std.signals; 64 | 65 | import core.exception : onOutOfMemoryError; 66 | import core.stdc.stdlib : calloc, realloc, free; 67 | import std.stdio; 68 | 69 | // Special function for internal use only. 70 | // Use of this is where the slot had better be a delegate 71 | // to an object or an interface that is part of an object. 72 | extern (C) Object _d_toObject(void* p); 73 | 74 | // Used in place of Object.notifyRegister and Object.notifyUnRegister. 75 | alias DisposeEvt = void delegate(Object); 76 | extern (C) void rt_attachDisposeEvent( Object obj, DisposeEvt evt ); 77 | extern (C) void rt_detachDisposeEvent( Object obj, DisposeEvt evt ); 78 | //debug=signal; 79 | 80 | /************************ 81 | * Mixin to create a signal within a class object. 82 | * 83 | * Different signals can be added to a class by naming the mixins. 84 | */ 85 | 86 | mixin template Signal(T1...) 87 | { 88 | static import core.exception; 89 | static import core.stdc.stdlib; 90 | /*** 91 | * A slot is implemented as a delegate. 92 | * The slot_t is the type of the delegate. 93 | * The delegate must be to an instance of a class or an interface 94 | * to a class instance. 95 | * Delegates to struct instances or nested functions must not be 96 | * used as slots. 97 | */ 98 | alias slot_t = void delegate(T1); 99 | 100 | /*** 101 | * Call each of the connected slots, passing the argument(s) i to them. 102 | * Nested call will be ignored. 103 | */ 104 | final void emit( T1 i ) 105 | { 106 | if (status >= ST.inemitting || !slots.length) 107 | return; // should not nest 108 | 109 | status = ST.inemitting; 110 | scope (exit) 111 | status = ST.idle; 112 | 113 | foreach (slot; slots[0 .. slots_idx]) 114 | { if (slot) 115 | slot(i); 116 | } 117 | 118 | assert(status >= ST.inemitting); 119 | if (status == ST.inemitting_disconnected) 120 | { 121 | for (size_t j = 0; j < slots_idx;) 122 | { 123 | if (slots[j] is null) 124 | { 125 | slots_idx--; 126 | slots[j] = slots[slots_idx]; 127 | } 128 | else 129 | j++; 130 | } 131 | } 132 | } 133 | 134 | /*** 135 | * Add a slot to the list of slots to be called when emit() is called. 136 | */ 137 | final void connect(slot_t slot) 138 | { 139 | /* Do this: 140 | * slots ~= slot; 141 | * but use malloc() and friends instead 142 | */ 143 | auto len = slots.length; 144 | if (slots_idx == len) 145 | { 146 | if (slots.length == 0) 147 | { 148 | len = 4; 149 | auto p = core.stdc.stdlib.calloc(slot_t.sizeof, len); 150 | if (!p) 151 | core.exception.onOutOfMemoryError(); 152 | slots = (cast(slot_t*) p)[0 .. len]; 153 | } 154 | else 155 | { 156 | import core.checkedint : addu, mulu; 157 | bool overflow; 158 | len = addu(mulu(len, 2, overflow), 4, overflow); // len = len * 2 + 4 159 | const nbytes = mulu(len, slot_t.sizeof, overflow); 160 | if (overflow) assert(0); 161 | 162 | auto p = core.stdc.stdlib.realloc(slots.ptr, nbytes); 163 | if (!p) 164 | core.exception.onOutOfMemoryError(); 165 | slots = (cast(slot_t*) p)[0 .. len]; 166 | slots[slots_idx + 1 .. $] = null; 167 | } 168 | } 169 | slots[slots_idx++] = slot; 170 | 171 | L1: 172 | Object o = _d_toObject(slot.ptr); 173 | rt_attachDisposeEvent(o, &unhook); 174 | } 175 | 176 | /*** 177 | * Remove a slot from the list of slots to be called when emit() is called. 178 | */ 179 | final void disconnect(slot_t slot) 180 | { 181 | debug (signal) writefln("Signal.disconnect(slot)"); 182 | size_t disconnectedSlots = 0; 183 | size_t instancePreviousSlots = 0; 184 | if (status >= ST.inemitting) 185 | { 186 | foreach (i, sloti; slots[0 .. slots_idx]) 187 | { 188 | if (sloti.ptr == slot.ptr && 189 | ++instancePreviousSlots && 190 | sloti == slot) 191 | { 192 | disconnectedSlots++; 193 | slots[i] = null; 194 | status = ST.inemitting_disconnected; 195 | } 196 | } 197 | } 198 | else 199 | { 200 | for (size_t i = 0; i < slots_idx; ) 201 | { 202 | if (slots[i].ptr == slot.ptr && 203 | ++instancePreviousSlots && 204 | slots[i] == slot) 205 | { 206 | slots_idx--; 207 | disconnectedSlots++; 208 | slots[i] = slots[slots_idx]; 209 | slots[slots_idx] = null; // not strictly necessary 210 | } 211 | else 212 | i++; 213 | } 214 | } 215 | 216 | // detach object from dispose event if all its slots have been removed 217 | if (instancePreviousSlots == disconnectedSlots) 218 | { 219 | Object o = _d_toObject(slot.ptr); 220 | rt_detachDisposeEvent(o, &unhook); 221 | } 222 | } 223 | 224 | /*** 225 | * Disconnect all the slots. 226 | */ 227 | final void disconnectAll() 228 | { 229 | debug (signal) writefln("Signal.disconnectAll"); 230 | __dtor(); 231 | slots_idx = 0; 232 | status = ST.idle; 233 | } 234 | 235 | /* ** 236 | * Special function called when o is destroyed. 237 | * It causes any slots dependent on o to be removed from the list 238 | * of slots to be called by emit(). 239 | */ 240 | final void unhook(Object o) 241 | in { assert( status == ST.idle ); } 242 | do 243 | { 244 | debug (signal) writefln("Signal.unhook(o = %s)", cast(void*) o); 245 | for (size_t i = 0; i < slots_idx; ) 246 | { 247 | if (_d_toObject(slots[i].ptr) is o) 248 | { slots_idx--; 249 | slots[i] = slots[slots_idx]; 250 | slots[slots_idx] = null; // not strictly necessary 251 | } 252 | else 253 | i++; 254 | } 255 | } 256 | 257 | /* ** 258 | * There can be multiple destructors inserted by mixins. 259 | */ 260 | ~this() 261 | { 262 | /* ** 263 | * When this object is destroyed, need to let every slot 264 | * know that this object is destroyed so they are not left 265 | * with dangling references to it. 266 | */ 267 | if (slots.length) 268 | { 269 | foreach (slot; slots[0 .. slots_idx]) 270 | { 271 | if (slot) 272 | { Object o = _d_toObject(slot.ptr); 273 | rt_detachDisposeEvent(o, &unhook); 274 | } 275 | } 276 | core.stdc.stdlib.free(slots.ptr); 277 | slots = null; 278 | } 279 | } 280 | 281 | private: 282 | slot_t[] slots; // the slots to call from emit() 283 | size_t slots_idx; // used length of slots[] 284 | 285 | enum ST { idle, inemitting, inemitting_disconnected } 286 | ST status; 287 | } 288 | 289 | /// 290 | @system unittest 291 | { 292 | import std.signals; 293 | 294 | int observedMessageCounter = 0; 295 | 296 | class Observer 297 | { // our slot 298 | void watch(string msg, int value) 299 | { 300 | switch (observedMessageCounter++) 301 | { 302 | case 0: 303 | assert(msg == "setting new value"); 304 | assert(value == 4); 305 | break; 306 | case 1: 307 | assert(msg == "setting new value"); 308 | assert(value == 6); 309 | break; 310 | default: 311 | assert(0, "Unknown observation"); 312 | } 313 | } 314 | } 315 | 316 | class Observer2 317 | { // our slot 318 | void watch(string msg, int value) 319 | { 320 | } 321 | } 322 | 323 | class Foo 324 | { 325 | int value() { return _value; } 326 | 327 | int value(int v) 328 | { 329 | if (v != _value) 330 | { _value = v; 331 | // call all the connected slots with the two parameters 332 | emit("setting new value", v); 333 | } 334 | return v; 335 | } 336 | 337 | // Mix in all the code we need to make Foo into a signal 338 | mixin Signal!(string, int); 339 | 340 | private : 341 | int _value; 342 | } 343 | 344 | Foo a = new Foo; 345 | Observer o = new Observer; 346 | auto o2 = new Observer2; 347 | auto o3 = new Observer2; 348 | auto o4 = new Observer2; 349 | auto o5 = new Observer2; 350 | 351 | a.value = 3; // should not call o.watch() 352 | a.connect(&o.watch); // o.watch is the slot 353 | a.connect(&o2.watch); 354 | a.connect(&o3.watch); 355 | a.connect(&o4.watch); 356 | a.connect(&o5.watch); 357 | a.value = 4; // should call o.watch() 358 | a.disconnect(&o.watch); // o.watch is no longer a slot 359 | a.disconnect(&o3.watch); 360 | a.disconnect(&o5.watch); 361 | a.disconnect(&o4.watch); 362 | a.disconnect(&o2.watch); 363 | a.value = 5; // so should not call o.watch() 364 | a.connect(&o2.watch); 365 | a.connect(&o.watch); // connect again 366 | a.value = 6; // should call o.watch() 367 | destroy(o); // destroying o should automatically disconnect it 368 | a.value = 7; // should not call o.watch() 369 | 370 | assert(observedMessageCounter == 2); 371 | } 372 | 373 | // A function whose sole purpose is to get this module linked in 374 | // so the unittest will run. 375 | void linkin() { } 376 | 377 | @system unittest 378 | { 379 | class Observer 380 | { 381 | void watch(string msg, int i) 382 | { 383 | //writefln("Observed msg '%s' and value %s", msg, i); 384 | captured_value = i; 385 | captured_msg = msg; 386 | } 387 | 388 | int captured_value; 389 | string captured_msg; 390 | } 391 | 392 | class Foo 393 | { 394 | @property int value() { return _value; } 395 | 396 | @property int value(int v) 397 | { 398 | if (v != _value) 399 | { _value = v; 400 | emit("setting new value", v); 401 | } 402 | return v; 403 | } 404 | 405 | mixin Signal!(string, int); 406 | 407 | private: 408 | int _value; 409 | } 410 | 411 | Foo a = new Foo; 412 | Observer o = new Observer; 413 | 414 | // check initial condition 415 | assert(o.captured_value == 0); 416 | assert(o.captured_msg == ""); 417 | 418 | // set a value while no observation is in place 419 | a.value = 3; 420 | assert(o.captured_value == 0); 421 | assert(o.captured_msg == ""); 422 | 423 | // connect the watcher and trigger it 424 | a.connect(&o.watch); 425 | a.value = 4; 426 | assert(o.captured_value == 4); 427 | assert(o.captured_msg == "setting new value"); 428 | 429 | // disconnect the watcher and make sure it doesn't trigger 430 | a.disconnect(&o.watch); 431 | a.value = 5; 432 | assert(o.captured_value == 4); 433 | assert(o.captured_msg == "setting new value"); 434 | 435 | // reconnect the watcher and make sure it triggers 436 | a.connect(&o.watch); 437 | a.value = 6; 438 | assert(o.captured_value == 6); 439 | assert(o.captured_msg == "setting new value"); 440 | 441 | // destroy the underlying object and make sure it doesn't cause 442 | // a crash or other problems 443 | destroy(o); 444 | a.value = 7; 445 | } 446 | 447 | @system unittest 448 | { 449 | class Observer 450 | { 451 | int i; 452 | long l; 453 | string str; 454 | 455 | void watchInt(string str, int i) 456 | { 457 | this.str = str; 458 | this.i = i; 459 | } 460 | 461 | void watchLong(string str, long l) 462 | { 463 | this.str = str; 464 | this.l = l; 465 | } 466 | } 467 | 468 | class Bar 469 | { 470 | @property void value1(int v) { s1.emit("str1", v); } 471 | @property void value2(int v) { s2.emit("str2", v); } 472 | @property void value3(long v) { s3.emit("str3", v); } 473 | 474 | mixin Signal!(string, int) s1; 475 | mixin Signal!(string, int) s2; 476 | mixin Signal!(string, long) s3; 477 | } 478 | 479 | void test(T)(T a) { 480 | auto o1 = new Observer; 481 | auto o2 = new Observer; 482 | auto o3 = new Observer; 483 | 484 | // connect the watcher and trigger it 485 | a.s1.connect(&o1.watchInt); 486 | a.s2.connect(&o2.watchInt); 487 | a.s3.connect(&o3.watchLong); 488 | 489 | assert(!o1.i && !o1.l && o1.str == null); 490 | assert(!o2.i && !o2.l && o2.str == null); 491 | assert(!o3.i && !o3.l && o3.str == null); 492 | 493 | a.value1 = 11; 494 | assert(o1.i == 11 && !o1.l && o1.str == "str1"); 495 | assert(!o2.i && !o2.l && o2.str == null); 496 | assert(!o3.i && !o3.l && o3.str == null); 497 | o1.i = -11; o1.str = "x1"; 498 | 499 | a.value2 = 12; 500 | assert(o1.i == -11 && !o1.l && o1.str == "x1"); 501 | assert(o2.i == 12 && !o2.l && o2.str == "str2"); 502 | assert(!o3.i && !o3.l && o3.str == null); 503 | o2.i = -12; o2.str = "x2"; 504 | 505 | a.value3 = 13; 506 | assert(o1.i == -11 && !o1.l && o1.str == "x1"); 507 | assert(o2.i == -12 && !o1.l && o2.str == "x2"); 508 | assert(!o3.i && o3.l == 13 && o3.str == "str3"); 509 | o3.l = -13; o3.str = "x3"; 510 | 511 | // disconnect the watchers and make sure it doesn't trigger 512 | a.s1.disconnect(&o1.watchInt); 513 | a.s2.disconnect(&o2.watchInt); 514 | a.s3.disconnect(&o3.watchLong); 515 | 516 | a.value1 = 21; 517 | a.value2 = 22; 518 | a.value3 = 23; 519 | assert(o1.i == -11 && !o1.l && o1.str == "x1"); 520 | assert(o2.i == -12 && !o1.l && o2.str == "x2"); 521 | assert(!o3.i && o3.l == -13 && o3.str == "x3"); 522 | 523 | // reconnect the watcher and make sure it triggers 524 | a.s1.connect(&o1.watchInt); 525 | a.s2.connect(&o2.watchInt); 526 | a.s3.connect(&o3.watchLong); 527 | 528 | a.value1 = 31; 529 | a.value2 = 32; 530 | a.value3 = 33; 531 | assert(o1.i == 31 && !o1.l && o1.str == "str1"); 532 | assert(o2.i == 32 && !o1.l && o2.str == "str2"); 533 | assert(!o3.i && o3.l == 33 && o3.str == "str3"); 534 | 535 | // destroy observers 536 | destroy(o1); 537 | destroy(o2); 538 | destroy(o3); 539 | a.value1 = 41; 540 | a.value2 = 42; 541 | a.value3 = 43; 542 | } 543 | 544 | test(new Bar); 545 | 546 | class BarDerived: Bar 547 | { 548 | @property void value4(int v) { s4.emit("str4", v); } 549 | @property void value5(int v) { s5.emit("str5", v); } 550 | @property void value6(long v) { s6.emit("str6", v); } 551 | 552 | mixin Signal!(string, int) s4; 553 | mixin Signal!(string, int) s5; 554 | mixin Signal!(string, long) s6; 555 | } 556 | 557 | auto a = new BarDerived; 558 | 559 | test!Bar(a); 560 | test!BarDerived(a); 561 | 562 | auto o4 = new Observer; 563 | auto o5 = new Observer; 564 | auto o6 = new Observer; 565 | 566 | // connect the watcher and trigger it 567 | a.s4.connect(&o4.watchInt); 568 | a.s5.connect(&o5.watchInt); 569 | a.s6.connect(&o6.watchLong); 570 | 571 | assert(!o4.i && !o4.l && o4.str == null); 572 | assert(!o5.i && !o5.l && o5.str == null); 573 | assert(!o6.i && !o6.l && o6.str == null); 574 | 575 | a.value4 = 44; 576 | assert(o4.i == 44 && !o4.l && o4.str == "str4"); 577 | assert(!o5.i && !o5.l && o5.str == null); 578 | assert(!o6.i && !o6.l && o6.str == null); 579 | o4.i = -44; o4.str = "x4"; 580 | 581 | a.value5 = 45; 582 | assert(o4.i == -44 && !o4.l && o4.str == "x4"); 583 | assert(o5.i == 45 && !o5.l && o5.str == "str5"); 584 | assert(!o6.i && !o6.l && o6.str == null); 585 | o5.i = -45; o5.str = "x5"; 586 | 587 | a.value6 = 46; 588 | assert(o4.i == -44 && !o4.l && o4.str == "x4"); 589 | assert(o5.i == -45 && !o4.l && o5.str == "x5"); 590 | assert(!o6.i && o6.l == 46 && o6.str == "str6"); 591 | o6.l = -46; o6.str = "x6"; 592 | 593 | // disconnect the watchers and make sure it doesn't trigger 594 | a.s4.disconnect(&o4.watchInt); 595 | a.s5.disconnect(&o5.watchInt); 596 | a.s6.disconnect(&o6.watchLong); 597 | 598 | a.value4 = 54; 599 | a.value5 = 55; 600 | a.value6 = 56; 601 | assert(o4.i == -44 && !o4.l && o4.str == "x4"); 602 | assert(o5.i == -45 && !o4.l && o5.str == "x5"); 603 | assert(!o6.i && o6.l == -46 && o6.str == "x6"); 604 | 605 | // reconnect the watcher and make sure it triggers 606 | a.s4.connect(&o4.watchInt); 607 | a.s5.connect(&o5.watchInt); 608 | a.s6.connect(&o6.watchLong); 609 | 610 | a.value4 = 64; 611 | a.value5 = 65; 612 | a.value6 = 66; 613 | assert(o4.i == 64 && !o4.l && o4.str == "str4"); 614 | assert(o5.i == 65 && !o4.l && o5.str == "str5"); 615 | assert(!o6.i && o6.l == 66 && o6.str == "str6"); 616 | 617 | // destroy observers 618 | destroy(o4); 619 | destroy(o5); 620 | destroy(o6); 621 | a.value4 = 44; 622 | a.value5 = 45; 623 | a.value6 = 46; 624 | } 625 | 626 | // Triggers bug from issue 15341 627 | @system unittest 628 | { 629 | class Observer 630 | { 631 | void watch() { } 632 | void watch2() { } 633 | } 634 | 635 | class Bar 636 | { 637 | mixin Signal!(); 638 | } 639 | 640 | auto a = new Bar; 641 | auto o = new Observer; 642 | 643 | //Connect both observer methods for the same instance 644 | a.connect(&o.watch); 645 | a.connect(&o.watch2); // not connecting watch2() or disconnecting it manually fixes the issue 646 | 647 | //Disconnect a single method of the two 648 | a.disconnect(&o.watch); // NOT disconnecting watch() fixes the issue 649 | 650 | destroy(o); // destroying o should automatically call unhook and disconnect the slot for watch2 651 | a.emit(); // should not raise segfault since &o.watch2 is no longer connected 652 | } 653 | 654 | version (none) // Disabled because of https://issues.dlang.org/show_bug.cgi?id=5028 655 | @system unittest 656 | { 657 | class A 658 | { 659 | mixin Signal!(string, int) s1; 660 | } 661 | 662 | class B : A 663 | { 664 | mixin Signal!(string, int) s2; 665 | } 666 | } 667 | 668 | // Triggers bug from issue 16249 669 | @system unittest 670 | { 671 | class myLINE 672 | { 673 | mixin Signal!( myLINE, int ); 674 | 675 | void value( int v ) 676 | { 677 | if ( v >= 0 ) emit( this, v ); 678 | else emit( new myLINE, v ); 679 | } 680 | } 681 | 682 | class Dot 683 | { 684 | int value; 685 | 686 | myLINE line_; 687 | void line( myLINE line_x ) 688 | { 689 | if ( line_ is line_x ) return; 690 | 691 | if ( line_ !is null ) 692 | { 693 | line_.disconnect( &watch ); 694 | } 695 | line_ = line_x; 696 | line_.connect( &watch ); 697 | } 698 | 699 | void watch( myLINE line_x, int value_x ) 700 | { 701 | line = line_x; 702 | value = value_x; 703 | } 704 | } 705 | 706 | auto dot1 = new Dot; 707 | auto dot2 = new Dot; 708 | auto line = new myLINE; 709 | dot1.line = line; 710 | dot2.line = line; 711 | 712 | line.value = 11; 713 | assert( dot1.value == 11 ); 714 | assert( dot2.value == 11 ); 715 | 716 | line.value = -22; 717 | assert( dot1.value == -22 ); 718 | assert( dot2.value == -22 ); 719 | } 720 | 721 | @system unittest 722 | { 723 | import std.signals; 724 | 725 | class Observer 726 | { // our slot 727 | void watch(string msg, int value) 728 | { 729 | if (value != 0) 730 | { 731 | assert(msg == "setting new value"); 732 | assert(value == 1); 733 | } 734 | } 735 | } 736 | 737 | class Foo 738 | { 739 | int value() { return _value; } 740 | 741 | int value(int v) 742 | { 743 | if (v != _value) 744 | { 745 | _value = v; 746 | // call all the connected slots with the parameters 747 | emit("setting new value", v); 748 | } 749 | return v; 750 | } 751 | 752 | // Mix in all the code we need to make Foo into a signal 753 | mixin Signal!(string, int); 754 | 755 | private : 756 | int _value; 757 | } 758 | 759 | Foo a = new Foo; 760 | Observer o = new Observer; 761 | auto o2 = new Observer; 762 | 763 | a.value = 3; // should not call o.watch() 764 | a.connect(&o.watch); // o.watch is the slot 765 | a.connect(&o2.watch); 766 | a.value = 1; // should call o.watch() 767 | a.disconnectAll(); 768 | a.value = 5; // so should not call o.watch() 769 | a.connect(&o.watch); // connect again 770 | a.connect(&o2.watch); 771 | a.value = 1; // should call o.watch() 772 | destroy(o); // destroying o should automatically disconnect it 773 | destroy(o2); 774 | a.value = 7; // should not call o.watch() 775 | } 776 | -------------------------------------------------------------------------------- /src/undead/socketstream.d: -------------------------------------------------------------------------------- 1 | // Written in the D programming language 2 | 3 | /* 4 | Copyright (C) 2004 Christopher E. Miller 5 | 6 | This software is provided 'as-is', without any express or implied 7 | warranty. In no event will the authors be held liable for any damages 8 | arising from the use of this software. 9 | 10 | Permission is granted to anyone to use this software for any purpose, 11 | including commercial applications, and to alter it and redistribute it 12 | freely, subject to the following restrictions: 13 | 14 | 1. The origin of this software must not be misrepresented; you must not 15 | claim that you wrote the original software. If you use this software 16 | in a product, an acknowledgment in the product documentation would be 17 | appreciated but is not required. 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 3. This notice may not be removed or altered from any source distribution. 21 | */ 22 | 23 | /************** 24 | * $(RED Deprecated: This module is considered out-dated and not up to Phobos' 25 | * current standards.) 26 | * 27 | * $(D SocketStream) is a stream for a blocking, 28 | * connected $(D Socket). 29 | * 30 | * Example: 31 | * See $(SAMPLESRC htmlget.d) 32 | * Authors: Christopher E. Miller 33 | * References: 34 | * $(LINK2 std_stream.html, std.stream) 35 | * Source: $(PHOBOSSRC std/_socketstream.d) 36 | * Macros: WIKI=Phobos/StdSocketstream 37 | */ 38 | module undead.socketstream; 39 | 40 | private import undead.stream; 41 | private import std.socket; 42 | 43 | /************** 44 | * $(D SocketStream) is a stream for a blocking, 45 | * connected $(D Socket). 46 | */ 47 | class SocketStream: Stream 48 | { 49 | private: 50 | Socket sock; 51 | 52 | public: 53 | 54 | /** 55 | * Constructs a SocketStream with the specified Socket and FileMode flags. 56 | */ 57 | this(Socket sock, FileMode mode) 58 | { 59 | if(mode & FileMode.In) 60 | readable = true; 61 | if(mode & FileMode.Out) 62 | writeable = true; 63 | 64 | this.sock = sock; 65 | } 66 | 67 | /** 68 | * Uses mode $(D FileMode.In | FileMode.Out). 69 | */ 70 | this(Socket sock) 71 | { 72 | writeable = readable = true; 73 | this.sock = sock; 74 | } 75 | 76 | /** 77 | * Property to get the $(D Socket) that is being streamed. 78 | */ 79 | Socket socket() 80 | { 81 | return sock; 82 | } 83 | 84 | /** 85 | * Attempts to read the entire block, waiting if necessary. 86 | */ 87 | override size_t readBlock(void* _buffer, size_t size) 88 | { 89 | ubyte* buffer = cast(ubyte*)_buffer; 90 | assertReadable(); 91 | 92 | if (size == 0) 93 | return size; 94 | 95 | auto len = sock.receive(buffer[0 .. size]); 96 | readEOF = cast(bool)(len == 0); 97 | if (len == sock.ERROR) 98 | len = 0; 99 | return len; 100 | } 101 | 102 | /** 103 | * Attempts to write the entire block, waiting if necessary. 104 | */ 105 | override size_t writeBlock(const void* _buffer, size_t size) 106 | { 107 | ubyte* buffer = cast(ubyte*)_buffer; 108 | assertWriteable(); 109 | 110 | if (size == 0) 111 | return size; 112 | 113 | auto len = sock.send(buffer[0 .. size]); 114 | readEOF = cast(bool)(len == 0); 115 | if (len == sock.ERROR) 116 | len = 0; 117 | return len; 118 | } 119 | 120 | /** 121 | * Socket streams do not support seeking. This disabled method throws 122 | * a $(D SeekException). 123 | */ 124 | override ulong seek(long offset, SeekPos whence) 125 | { 126 | throw new SeekException("Cannot seek a socket."); 127 | } 128 | 129 | /** 130 | * Does not return the entire stream because that would 131 | * require the remote connection to be closed. 132 | */ 133 | override string toString() 134 | { 135 | return sock.toString(); 136 | } 137 | 138 | /** 139 | * Close the $(D Socket). 140 | */ 141 | override void close() 142 | { 143 | sock.close(); 144 | super.close(); 145 | } 146 | } 147 | 148 | -------------------------------------------------------------------------------- /src/undead/string.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains the obsolete pattern matching functions from Phobos' 3 | * `std.string`. 4 | */ 5 | module undead.string; 6 | 7 | import std.traits; 8 | 9 | /*********************************************** 10 | * See if character c is in the pattern. 11 | * Patterns: 12 | * 13 | * A $(I pattern) is an array of characters much like a $(I character 14 | * class) in regular expressions. A sequence of characters 15 | * can be given, such as "abcde". The '-' can represent a range 16 | * of characters, as "a-e" represents the same pattern as "abcde". 17 | * "a-fA-F0-9" represents all the hex characters. 18 | * If the first character of a pattern is '^', then the pattern 19 | * is negated, i.e. "^0-9" means any character except a digit. 20 | * The functions inPattern, $(B countchars), $(B removeschars), 21 | * and $(B squeeze) use patterns. 22 | * 23 | * Note: In the future, the pattern syntax may be improved 24 | * to be more like regular expression character classes. 25 | */ 26 | bool inPattern(S)(dchar c, in S pattern) @safe pure @nogc 27 | if (isSomeString!S) 28 | { 29 | bool result = false; 30 | int range = 0; 31 | dchar lastc; 32 | 33 | foreach (size_t i, dchar p; pattern) 34 | { 35 | if (p == '^' && i == 0) 36 | { 37 | result = true; 38 | if (i + 1 == pattern.length) 39 | return (c == p); // or should this be an error? 40 | } 41 | else if (range) 42 | { 43 | range = 0; 44 | if (lastc <= c && c <= p || c == p) 45 | return !result; 46 | } 47 | else if (p == '-' && i > result && i + 1 < pattern.length) 48 | { 49 | range = 1; 50 | continue; 51 | } 52 | else if (c == p) 53 | return !result; 54 | lastc = p; 55 | } 56 | return result; 57 | } 58 | 59 | 60 | @safe pure @nogc unittest 61 | { 62 | assertCTFEable!( 63 | { 64 | assert(inPattern('x', "x") == 1); 65 | assert(inPattern('x', "y") == 0); 66 | assert(inPattern('x', string.init) == 0); 67 | assert(inPattern('x', "^y") == 1); 68 | assert(inPattern('x', "yxxy") == 1); 69 | assert(inPattern('x', "^yxxy") == 0); 70 | assert(inPattern('x', "^abcd") == 1); 71 | assert(inPattern('^', "^^") == 0); 72 | assert(inPattern('^', "^") == 1); 73 | assert(inPattern('^', "a^") == 1); 74 | assert(inPattern('x', "a-z") == 1); 75 | assert(inPattern('x', "A-Z") == 0); 76 | assert(inPattern('x', "^a-z") == 0); 77 | assert(inPattern('x', "^A-Z") == 1); 78 | assert(inPattern('-', "a-") == 1); 79 | assert(inPattern('-', "^A-") == 0); 80 | assert(inPattern('a', "z-a") == 1); 81 | assert(inPattern('z', "z-a") == 1); 82 | assert(inPattern('x', "z-a") == 0); 83 | }); 84 | } 85 | 86 | 87 | /** 88 | * See if character c is in the intersection of the patterns. 89 | */ 90 | bool inPattern(S)(dchar c, S[] patterns) @safe pure @nogc 91 | if (isSomeString!S) 92 | { 93 | foreach (string pattern; patterns) 94 | { 95 | if (!inPattern(c, pattern)) 96 | { 97 | return false; 98 | } 99 | } 100 | return true; 101 | } 102 | 103 | 104 | /** 105 | * Count characters in s that match pattern. 106 | */ 107 | size_t countchars(S, S1)(S s, in S1 pattern) @safe pure @nogc 108 | if (isSomeString!S && isSomeString!S1) 109 | { 110 | size_t count; 111 | foreach (dchar c; s) 112 | { 113 | count += inPattern(c, pattern); 114 | } 115 | return count; 116 | } 117 | 118 | @safe pure @nogc unittest 119 | { 120 | assertCTFEable!( 121 | { 122 | assert(countchars("abc", "a-c") == 3); 123 | assert(countchars("hello world", "or") == 3); 124 | }); 125 | } 126 | 127 | 128 | /** 129 | * Return string that is s with all characters removed that match pattern. 130 | */ 131 | S removechars(S)(S s, in S pattern) @safe pure 132 | if (isSomeString!S) 133 | { 134 | import std.utf : encode; 135 | 136 | Unqual!(typeof(s[0]))[] r; 137 | bool changed = false; 138 | 139 | foreach (size_t i, dchar c; s) 140 | { 141 | if (inPattern(c, pattern)) 142 | { 143 | if (!changed) 144 | { 145 | changed = true; 146 | r = s[0 .. i].dup; 147 | } 148 | continue; 149 | } 150 | if (changed) 151 | { 152 | encode(r, c); 153 | } 154 | } 155 | if (changed) 156 | return r; 157 | else 158 | return s; 159 | } 160 | 161 | @safe pure unittest 162 | { 163 | assertCTFEable!( 164 | { 165 | assert(removechars("abc", "a-c").length == 0); 166 | assert(removechars("hello world", "or") == "hell wld"); 167 | assert(removechars("hello world", "d") == "hello worl"); 168 | assert(removechars("hah", "h") == "a"); 169 | }); 170 | } 171 | 172 | @safe pure unittest 173 | { 174 | assert(removechars("abc", "x") == "abc"); 175 | } 176 | 177 | 178 | /*************************************************** 179 | * Return string where sequences of a character in s[] from pattern[] 180 | * are replaced with a single instance of that character. 181 | * If pattern is null, it defaults to all characters. 182 | */ 183 | S squeeze(S)(S s, in S pattern = null) 184 | { 185 | import std.utf : encode, stride; 186 | 187 | Unqual!(typeof(s[0]))[] r; 188 | dchar lastc; 189 | size_t lasti; 190 | int run; 191 | bool changed; 192 | 193 | foreach (size_t i, dchar c; s) 194 | { 195 | if (run && lastc == c) 196 | { 197 | changed = true; 198 | } 199 | else if (pattern is null || inPattern(c, pattern)) 200 | { 201 | run = 1; 202 | if (changed) 203 | { 204 | if (r is null) 205 | r = s[0 .. lasti].dup; 206 | encode(r, c); 207 | } 208 | else 209 | lasti = i + stride(s, i); 210 | lastc = c; 211 | } 212 | else 213 | { 214 | run = 0; 215 | if (changed) 216 | { 217 | if (r is null) 218 | r = s[0 .. lasti].dup; 219 | encode(r, c); 220 | } 221 | } 222 | } 223 | return changed ? ((r is null) ? s[0 .. lasti] : cast(S) r) : s; 224 | } 225 | 226 | @system pure unittest 227 | { 228 | assertCTFEable!( 229 | { 230 | string s; 231 | 232 | assert(squeeze("hello") == "helo"); 233 | 234 | s = "abcd"; 235 | assert(squeeze(s) is s); 236 | s = "xyzz"; 237 | assert(squeeze(s).ptr == s.ptr); // should just be a slice 238 | 239 | assert(squeeze("hello goodbyee", "oe") == "hello godbye"); 240 | }); 241 | } 242 | 243 | /*************************************************************** 244 | Finds the position $(D_PARAM pos) of the first character in $(D_PARAM 245 | s) that does not match $(D_PARAM pattern) (in the terminology used by 246 | $(REF inPattern, std,string)). Updates $(D_PARAM s = 247 | s[pos..$]). Returns the slice from the beginning of the original 248 | (before update) string up to, and excluding, $(D_PARAM pos). 249 | 250 | The $(D_PARAM munch) function is mostly convenient for skipping 251 | certain category of characters (e.g. whitespace) when parsing 252 | strings. (In such cases, the return value is not used.) 253 | */ 254 | S1 munch(S1, S2)(ref S1 s, S2 pattern) @safe pure @nogc 255 | { 256 | size_t j = s.length; 257 | foreach (i, dchar c; s) 258 | { 259 | if (!inPattern(c, pattern)) 260 | { 261 | j = i; 262 | break; 263 | } 264 | } 265 | scope(exit) s = s[j .. $]; 266 | return s[0 .. j]; 267 | } 268 | 269 | /// 270 | @safe pure @nogc unittest 271 | { 272 | string s = "123abc"; 273 | string t = munch(s, "0123456789"); 274 | assert(t == "123" && s == "abc"); 275 | t = munch(s, "0123456789"); 276 | assert(t == "" && s == "abc"); 277 | } 278 | 279 | @safe pure @nogc unittest 280 | { 281 | string s = "123€abc"; 282 | string t = munch(s, "0123456789"); 283 | assert(t == "123" && s == "€abc"); 284 | t = munch(s, "0123456789"); 285 | assert(t == "" && s == "€abc"); 286 | t = munch(s, "£$€¥"); 287 | assert(t == "€" && s == "abc"); 288 | } 289 | 290 | // helper function for unit tests 291 | private @property void assertCTFEable(alias dg)() 292 | { 293 | static assert({ cast(void) dg(); return true; }()); 294 | cast(void) dg(); 295 | } -------------------------------------------------------------------------------- /src/undead/utf.d: -------------------------------------------------------------------------------- 1 | /** 2 | * Contains the obsolete functions from Phobos' `std.utf`. 3 | */ 4 | module undead.utf; 5 | 6 | import std.utf; 7 | import std.typecons; 8 | 9 | //deprecated("Removed October 2017. Please use std.utf.encode instead.") 10 | char[] toUTF8(return out char[4] buf, dchar c) nothrow @nogc @safe pure 11 | { 12 | const sz = encode!(Yes.useReplacementDchar)(buf, c); 13 | return buf[0 .. sz]; 14 | } 15 | 16 | //deprecated("Removed October 2017. Please use std.utf.encode instead.") 17 | wchar[] toUTF16(return ref wchar[2] buf, dchar c) nothrow @nogc @safe pure 18 | { 19 | const sz = encode!(Yes.useReplacementDchar)(buf, c); 20 | return buf[0 .. sz]; 21 | } 22 | -------------------------------------------------------------------------------- /win32.mak: -------------------------------------------------------------------------------- 1 | #_ win32.mak 2 | # Build win32 version of undead 3 | # Needs Digital Mars D compiler to build, available free from: 4 | # http://www.digitalmars.com/d/ 5 | 6 | DMD=dmd 7 | DEL=del 8 | S=src\undead 9 | O=obj 10 | B=bin 11 | 12 | TARGET=undead 13 | 14 | DFLAGS=-g -Isrc/ 15 | LFLAGS=-L/map/co 16 | #DFLAGS= 17 | #LFLAGS= 18 | 19 | .d.obj : 20 | $(DMD) -c $(DFLAGS) $* 21 | 22 | SRC= $S\bitarray.d $S\regexp.d $S\datebase.d $S\date.d $S\dateparse.d \ 23 | $S\cstream.d $S\stream.d $S\socketstream.d $S\doformat.d $S/string.d \ 24 | $S\internal\file.d 25 | 26 | SOURCE= $(SRC) win32.mak win64.mak posix.mak LICENSE README.md dub.json 27 | 28 | all: $B\$(TARGET).lib 29 | 30 | ################################################# 31 | 32 | $B\$(TARGET).lib : $(SRC) 33 | $(DMD) -lib -of$B\$(TARGET).lib $(SRC) $(DFLAGS) 34 | 35 | 36 | unittest : 37 | $(DMD) -unittest -main -cov -of$O\unittest.exe $(SRC) $(DFLAGS) 38 | $O\unittest.exe 39 | 40 | 41 | clean: 42 | $(DEL) $O\unittest.exe *.lst 43 | 44 | 45 | tolf: 46 | tolf $(SOURCE) 47 | 48 | 49 | detab: 50 | detab $(SRC) 51 | 52 | 53 | zip: detab tolf $(SOURCE) 54 | $(DEL) undead.zip 55 | zip32 undead $(SOURCE) 56 | -------------------------------------------------------------------------------- /win64.mak: -------------------------------------------------------------------------------- 1 | #_ win32.mak 2 | # Build win32 version of undead 3 | # Needs Digital Mars D compiler to build, available free from: 4 | # http://www.digitalmars.com/d/ 5 | 6 | DMD=dmd 7 | DEL=del 8 | S=src\undead 9 | O=obj 10 | B=bin 11 | 12 | TARGET=undead 13 | 14 | DFLAGS=-m64 -g -Isrc/ 15 | LFLAGS=-L/map/co 16 | #DFLAGS= 17 | #LFLAGS= 18 | 19 | .d.obj : 20 | $(DMD) -c $(DFLAGS) $* 21 | 22 | SRC= $S\bitarray.d $S\regexp.d $S\datebase.d $S\date.d $S\dateparse.d \ 23 | $S\cstream.d $S\stream.d $S\socketstream.d $S\doformat.d $S/string.d \ 24 | $S\internal\file.d 25 | 26 | SOURCE= $(SRC) win32.mak win64.mak posix.mak LICENSE README.md dub.json 27 | 28 | all: $B\$(TARGET).lib 29 | 30 | ################################################# 31 | 32 | $B\$(TARGET).lib : $(SRC) 33 | $(DMD) -lib -of$B\$(TARGET).lib $(SRC) $(DFLAGS) 34 | 35 | 36 | unittest : 37 | $(DMD) -unittest -main -cov -of$O\unittest.exe $(SRC) $(DFLAGS) 38 | $O\unittest.exe 39 | 40 | 41 | clean: 42 | $(DEL) $O\unittest.exe *.lst 43 | 44 | 45 | tolf: 46 | tolf $(SOURCE) 47 | 48 | 49 | detab: 50 | detab $(SRC) 51 | 52 | 53 | zip: detab tolf $(SOURCE) 54 | $(DEL) undead.zip 55 | zip32 undead $(SOURCE) 56 | --------------------------------------------------------------------------------