PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Backend/Runtime/BoaFile.cs

https://bitbucket.org/AdamMil/boaold
C# | 343 lines | 277 code | 46 blank | 20 comment | 39 complexity | 7e65148115c06d2464c4129cd38e0cd2 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Boa is the reference implementation for a language similar to Python,
  3. also called Boa. This implementation is both interpreted and compiled,
  4. targeting the Microsoft .NET Framework.
  5. http://www.adammil.net/
  6. Copyright (C) 2004-2005 Adam Milazzo
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. using System;
  20. using System.Collections;
  21. using System.IO;
  22. namespace Boa.Runtime
  23. {
  24. #region FileEnumerator
  25. public class FileEnumerator : IEnumerator
  26. { public FileEnumerator(IFile file) { this.file=file; state=State.BOF; }
  27. public object Current
  28. { get
  29. { if(state!=State.IN) throw new InvalidOperationException();
  30. return line;
  31. }
  32. }
  33. public bool MoveNext()
  34. { if(state==State.EOF) return false;
  35. line = file.readline();
  36. if(line==null) { state=State.EOF; return false; }
  37. state = State.IN; return true;
  38. }
  39. public void Reset() { file.seek(0); state=State.BOF; }
  40. enum State { BOF, IN, EOF };
  41. IFile file;
  42. string line;
  43. State state;
  44. }
  45. #endregion
  46. #region BoaFile
  47. [BoaType("file")]
  48. [DocString(@"file(filename[, mode[, bufsize]])
  49. file(stream)
  50. Return a new file object. In the first form, 'filename' is the file name to
  51. be opened and 'mode' indicates how the file is to be opened:
  52. 'r' for reading, 'w' for writing (truncating an existing file), and 'a'
  53. opens it for appending (which on some systems means that all writes append
  54. to the end of the file, regardless of the current seek position).
  55. Modes 'r+', 'w+' and 'a+' open the file for updating (note that 'w+'
  56. truncates the file). Append 'b' to the mode to open the file in binary mode,
  57. on systems that differentiate between binary and text files (else it is
  58. ignored). If the file cannot be opened, IOError is raised.
  59. If mode is omitted, it defaults to 'r'. When opening a binary file, you
  60. should append 'b' to the mode value for improved portability. (It's useful
  61. even on systems which don't treat binary and text files differently, where
  62. it serves as documentation.) The optional bufsize argument specifies the
  63. file's desired buffer size: 0 means unbuffered, 1 means line buffered, any
  64. other positive value means use a buffer of (approximately) that size.
  65. A negative bufsize means to use the system default, which is usually line
  66. buffered for tty devices and fully buffered for other files. If omitted,
  67. the system default is used.")]
  68. public class BoaFile : IFile, IEnumerable
  69. { public BoaFile(string filename) : this(File.Open(filename, FileMode.Open, FileAccess.Read))
  70. { source=filename; smode="r";
  71. }
  72. public BoaFile(string filename, string mode)
  73. { char type = 'r';
  74. bool plus=false;
  75. for(int i=0; i<mode.Length; i++)
  76. switch(mode[i])
  77. { case 'r': case 'w': case 'a': type=mode[i]; break;
  78. case '+': plus=true; break;
  79. case 'b': case 'U': break;
  80. default: throw Ops.ValueError("unrecognized character {0} in file mode", mode[i]);
  81. }
  82. FileMode fmode = type=='a' ? FileMode.Append : type=='w' ? FileMode.Create :
  83. plus ? FileMode.OpenOrCreate : FileMode.Open;
  84. FileAccess access = plus ? FileAccess.ReadWrite : type=='a' || type=='w' ? FileAccess.Write : FileAccess.Read;
  85. stream = File.Open(filename, fmode, access);
  86. source = filename;
  87. smode = mode;
  88. }
  89. public BoaFile(string filename, string mode, int bufsize) : this(filename, mode) { }
  90. public BoaFile(Stream stream) { this.stream = stream; source = "<stream>"; smode = string.Empty; }
  91. public string mode { get { return smode; } }
  92. public string name { get { return source; } }
  93. #region IEnumerable
  94. public IEnumerator GetEnumerator() { return new FileEnumerator(this); }
  95. #endregion
  96. #region IFile Members
  97. public bool canread { get { return stream.CanRead; } }
  98. public bool canseek { get { return stream.CanSeek; } }
  99. public bool canwrite { get { return stream.CanWrite; } }
  100. public bool closed { get { return stream==null; } }
  101. public System.Text.Encoding encoding { get { return enc; } set { enc = value; } }
  102. public int length { get { return (int)stream.Length; } }
  103. public void close()
  104. { if(stream!=null)
  105. { stream.Close();
  106. stream = null;
  107. }
  108. }
  109. public void flush()
  110. { AssertOpen();
  111. try { stream.Flush(); }
  112. catch(IOException e) { throw Ops.IOError(e.Message); }
  113. }
  114. public bool isatty() { throw Ops.NotImplementedError("isatty(): not implemented"); }
  115. public string next()
  116. { string line = readline();
  117. if(line==null) throw new StopIterationException();
  118. return line;
  119. }
  120. public byte[] read()
  121. { AssertOpen();
  122. if(stream.CanSeek) return read((int)(stream.Length-stream.Position));
  123. try
  124. { byte[] buf = new byte[4096];
  125. int total=0;
  126. while(true)
  127. { int toread = buf.Length-total, bytes = doread(buf, total, toread);
  128. total += bytes;
  129. if(bytes<toread) break;
  130. byte[] narr = new byte[buf.Length*2];
  131. buf.CopyTo(narr, 0);
  132. buf = narr;
  133. }
  134. if(total==buf.Length) return buf;
  135. byte[] ret = new byte[total];
  136. Array.Copy(buf, ret, total);
  137. return ret;
  138. }
  139. catch(IOException e) { throw Ops.IOError(e.Message); }
  140. }
  141. public string readstr() { return Encoding.GetString(read()); }
  142. public byte[] read(int bytes)
  143. { AssertOpen();
  144. try
  145. { byte[] buf = new byte[bytes];
  146. int read = doread(buf, 0, bytes);
  147. if(bytes==read) return buf;
  148. byte[] ret = new byte[read];
  149. Array.Copy(buf, ret, read);
  150. return ret;
  151. }
  152. catch(IOException e) { throw Ops.IOError(e.Message); }
  153. }
  154. public string readstr(int bytes) { return Encoding.GetString(read(bytes)); }
  155. public int readbyte()
  156. { AssertOpen();
  157. try
  158. { if(bufLen>0)
  159. { int ret = buf[0];
  160. Array.Copy(buf, 1, buf, 0, --bufLen); // this is really slow
  161. return ret;
  162. }
  163. return stream.ReadByte();
  164. }
  165. catch(IOException e) { throw Ops.IOError(e.Message); }
  166. }
  167. public string readline() { return readline(-1); }
  168. public string readline(int max)
  169. { AssertOpen();
  170. try
  171. { int pos=0;
  172. while(true)
  173. { if(bufLen>pos)
  174. { bool trimOne=false;
  175. int idx = Array.IndexOf(buf, (byte)'\n', pos, bufLen-pos);
  176. if(idx==-1)
  177. { idx = Array.IndexOf(buf, (byte)'\r', pos, bufLen-pos);
  178. if(idx!=-1) buf[idx] = (byte)'\n';
  179. }
  180. else if(idx>0 && buf[idx-1]=='\r') { trimOne=true; buf[--idx]=(byte)'\n'; }
  181. if(idx==-1) pos = bufLen;
  182. else
  183. { if(max>=0 && idx>max) { idx=max; trimOne=false; }
  184. string ret = Encoding.GetString(buf, 0, ++idx);
  185. if(trimOne) idx++;
  186. bufLen -= idx;
  187. if(bufLen>0) Array.Copy(buf, idx, buf, 0, bufLen);
  188. return ret;
  189. }
  190. }
  191. if(max>=0 && pos>=max)
  192. { string ret = Encoding.GetString(buf, 0, max);
  193. bufLen -= max;
  194. if(bufLen>0) Array.Copy(buf, max, buf, 0, bufLen);
  195. return ret;
  196. }
  197. int toread=128, read;
  198. if(bufLen+toread>buf.Length)
  199. { byte[] narr = new byte[buf.Length*2];
  200. Array.Copy(buf, narr, bufLen);
  201. buf = narr;
  202. }
  203. read = stream.Read(buf, bufLen, toread);
  204. if(read==0) break;
  205. bufLen += read;
  206. }
  207. if(bufLen==0) return null;
  208. else
  209. { string ret = Encoding.GetString(buf, 0, bufLen);
  210. bufLen = 0;
  211. return ret;
  212. }
  213. }
  214. catch(IOException e) { throw Ops.IOError(e.Message); }
  215. }
  216. public List readlines()
  217. { List list = new List();
  218. while(true)
  219. { string line = readline(-1);
  220. if(line==null) break;
  221. list.append(line);
  222. }
  223. return list;
  224. }
  225. public List readlines(int sizehint) { return readlines(); }
  226. public int seek(int offset) { return (int)stream.Seek(offset, SeekOrigin.Begin); }
  227. public int seek(int offset, int whence)
  228. { SeekOrigin origin = whence==1 ? SeekOrigin.Current : whence==2 ? SeekOrigin.End : SeekOrigin.Begin;
  229. return (int)stream.Seek(offset, origin);
  230. }
  231. public int tell() { return (int)stream.Position; }
  232. public void truncate() { truncate((int)stream.Position); }
  233. public void truncate(int size)
  234. { AssertOpen();
  235. try { clearBuffer(); stream.SetLength(size); }
  236. catch(IOException e) { throw Ops.IOError(e.Message); }
  237. }
  238. public void write(byte[] bytes) { write(bytes, 0, bytes.Length); }
  239. public void write(string str) { write(Encoding.GetBytes(str)); }
  240. public void writebyte(int value)
  241. { AssertOpen();
  242. try { clearBuffer(); stream.WriteByte((byte)value); }
  243. catch(IOException e) { throw Ops.IOError(e.Message); }
  244. }
  245. public void writelines(object sequence)
  246. { IEnumerator e = Ops.GetEnumerator(sequence);
  247. while(e.MoveNext()) write(Ops.ToString(e.Current));
  248. }
  249. #endregion
  250. public void write(byte[] bytes, int offset, int length)
  251. { AssertOpen();
  252. try { clearBuffer(); stream.Write(bytes, offset, length); }
  253. catch(IOException e) { throw Ops.IOError(e.Message); }
  254. }
  255. System.Text.Encoding Encoding { get { return enc==null ? System.Text.Encoding.Default : enc; } }
  256. void AssertOpen() { if(stream==null) throw Ops.IOError("operation attempted on a closed file"); }
  257. void clearBuffer()
  258. { if(bufLen>0 && stream.CanSeek)
  259. { stream.Position -= bufLen;
  260. bufLen = 0;
  261. }
  262. }
  263. int doread(byte[] buffer, int offset, int length)
  264. { if(length==0) return 0;
  265. int total=0;
  266. if(bufLen>0)
  267. { int tocopy = Math.Min(length, bufLen);
  268. Array.Copy(buf, 0, buffer, offset, tocopy);
  269. bufLen -= tocopy;
  270. if(bufLen>0) Array.Copy(buf, tocopy, buf, 0, bufLen);
  271. total += tocopy;
  272. length -= tocopy;
  273. if(length==0) return total;
  274. offset += tocopy;
  275. }
  276. while(true)
  277. { int read = stream.Read(buffer, offset, length);
  278. if(read==0) return total;
  279. total += read;
  280. length -= read;
  281. if(length==0) return total;
  282. offset += read;
  283. }
  284. }
  285. System.Text.Encoding enc;
  286. Stream stream;
  287. string source, smode;
  288. byte[] buf = new byte[128];
  289. int bufLen;
  290. }
  291. #endregion
  292. } // namespace Boa.Runtime