1 /** 2 * Betterc: Frequently used primitives suitable for use in the BetterC D subset. 3 * 4 * Copyright: Maxim Freck, 2018. 5 * Authors: Maxim Freck <maxim@freck.pp.ru> 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module betterc.file; 9 10 /******* 11 * Encapsulates a $(D FILE*). 12 */ 13 struct File { 14 private import core.stdc.stdio;//: SEEK_SET, SEEK_CUR, SEEK_END, FILE; 15 private import core.stdc.stdlib: malloc, free; 16 private import betterc.stringz: Stringz; 17 18 /// Offset is relative to the beginning 19 enum seekSet = SEEK_SET; 20 /// Offset is relative to the current position 21 enum seekCur = SEEK_CUR; 22 /// Offset is relative to the end 23 enum seekEnd = SEEK_END; 24 25 26 private struct Payload { 27 Stringz filename; 28 FILE *fd; 29 30 size_t count; 31 @disable this(this); // not copyable 32 } 33 34 private Payload *payload; 35 36 /******* 37 * Creates a temporary file without a name 38 */ 39 public static typeof(this) tmpfile() nothrow @nogc 40 { 41 return File(core.stdc.stdio.tmpfile()); 42 } 43 44 private this(FILE *f) nothrow @nogc 45 { 46 payload = (cast(Payload*)malloc(Payload.sizeof)); 47 payload.filename = Stringz(""); 48 payload.fd = f; 49 payload.count = 1; 50 } 51 52 /******* 53 * Constructor 54 * 55 * Params: 56 * filename = Null terminated file name 57 * mode = Null terminated access mode 58 */ 59 public this(string filename, in string mode) nothrow @nogc 60 { 61 payload = (cast(Payload*)malloc(Payload.sizeof)); 62 payload.filename = Stringz(filename); 63 payload.fd = fopen(*payload.filename, *Stringz(mode)); 64 payload.count = 1; 65 } 66 67 this (this) nothrow @nogc 68 { 69 if (payload !is null) 70 payload.count++; 71 } 72 73 ///Ref. counting during structure assignation 74 ref typeof(this) opAssign(ref typeof(this) rhs) 75 { 76 this.payload = rhs.payload; 77 if (payload !is null) 78 payload.count++; 79 80 return this; 81 } 82 83 ~this() nothrow @nogc 84 { 85 if (payload !is null && --payload.count == 0) { 86 this.close(); 87 free(payload); 88 } 89 } 90 91 92 /******* 93 * Reuses stream to change its access mode. 94 * 95 * Params: 96 * mode = Null terminated access mode 97 */ 98 public void reopen(in string mode) nothrow @nogc 99 { 100 payload.fd = freopen(*payload.filename, *Stringz(mode), payload.fd); 101 } 102 103 /******* 104 * Returns underlying FILE* 105 */ 106 public FILE* stream() nothrow @nogc 107 { 108 return payload.fd; 109 } 110 111 ///ditto 112 pragma(inline) 113 FILE* opUnary(string s)() nothrow @nogc if (s == "*") 114 { 115 return payload.fd; 116 } 117 118 //--- 119 public size_t read(void* ptr, size_t size, size_t nmemb) nothrow @nogc 120 { 121 return fread(ptr, size, nmemb, payload.fd); 122 } 123 124 ///ditto 125 public size_t read(T)(T[] buf) nothrow @nogc 126 { 127 //dbg("\nReading to ptr %u %u items of %u size\n", buf.ptr, buf.length, T.sizeof); 128 return read(buf.ptr, T.sizeof, buf.length); 129 } 130 131 132 ///--- 133 public size_t write(in void* ptr, size_t size, size_t nmemb) nothrow @nogc 134 { 135 return fwrite(ptr, size, nmemb, payload.fd); 136 } 137 138 ///ditto 139 public size_t write(T)(in T[] buf) nothrow @nogc 140 { 141 return write(buf.ptr, T.sizeof, buf.length); 142 } 143 144 145 146 ref typeof(this) opBinary(char* op, T)(in T[] pos) if (op == "<<") 147 { 148 write(buf.ptr, T.sizeof, buf.length); 149 return this; 150 } 151 152 //--- 153 public size_t read(T)(ref T b) nothrow @nogc 154 { 155 return read(&b, T.sizeof, 1); 156 } 157 158 public size_t write(T)(in T b) nothrow @nogc 159 { 160 return write(&b, T.sizeof, 1); 161 } 162 163 ref typeof(this) opBinary(char* op, T)(in T b) if (op == "<<") 164 { 165 write(&b, T.sizeof, 1); 166 return this; 167 } 168 169 ref typeof(this) opBinary(char* op)(string str) if (op == "<<") 170 { 171 write(str.ptr, 1, str.length); 172 return this; 173 } 174 175 /+++ It's broken at the moment 176 extern(C) public int dprintf(string format, ...) nothrow @nogc 177 { 178 va_list args; 179 va_start(args, format); 180 return vfprintf(payload.fd, *Stringz(format), args); 181 } 182 183 extern(C) public int printf(in char* format, ...) nothrow @nogc 184 { 185 va_list args; 186 va_start(args, format); 187 return vfprintf(payload.fd, format, args); 188 } 189 +++/ 190 191 public size_t length() nothrow @nogc 192 { 193 immutable auto seekSave = ftell(payload.fd); 194 fseek(payload.fd, 0, SEEK_END); 195 auto fileSize = ftell(payload.fd); 196 fseek(payload.fd, seekSave, SEEK_SET); 197 return fileSize; 198 } 199 200 public bool eof() nothrow @nogc 201 { 202 return feof(payload.fd) > 0; 203 } 204 205 public bool seek(size_t offset, int origin) nothrow @nogc 206 { 207 return fseek(payload.fd, cast(int)offset, origin) == 0; 208 } 209 210 public bool error() nothrow @nogc 211 { 212 return ferror(payload.fd) > 0; 213 } 214 215 public bool flush() nothrow @nogc 216 { 217 return fflush(payload.fd) == 0; 218 } 219 220 public void close() nothrow @nogc 221 { 222 if (payload.fd == null) return; 223 224 fclose(payload.fd); 225 payload.fd = null; 226 } 227 }