1 module esstool.reader;
2 
3 import esstool.arrayutil : count, len;
4 
5 @safe unittest
6 {
7     static void main(string[] args)
8     {
9         string[] stringList = new string[0];
10         LineReader reader = new LineReader("./LICENSE"); // The license <Mozilla Public License v2.0>
11         while (reader.readly())
12         {
13             stringList = stringList ~ [reader.read()];
14         }
15 
16         assert(stringList == readline("./LICENSE"));
17     }
18 }
19 
20 /**
21  * Read all lines in file.
22  * Params:
23  *   file = The file input;
24  * Returns: All texts in file input.
25  */
26 string[] readlines(string file)
27 {
28     import std.container : Array;
29 
30     auto arr = new Array!string();
31 
32     LineReader reader = new LineReader(file);
33     while (reader.readly())
34     {
35         arr.insertBack(reader.read());
36     }
37 
38     return arr.data();
39 }
40 
41 interface IReader
42 {
43     /**
44      * Read raw byte from file.
45      */
46     public ubyte[] readRaw();
47 
48     /**
49     * Read text from file.
50     */
51     public string read();
52 }
53 
54 class LineReader : IReader
55 {
56     private ubyte[] bufferedArray;
57     private ubyte[] buffered;
58 
59     this(string filePath)
60     {
61         import std.file : read, exists, isFile, FileException;
62 
63         if (!exists(filePath) || !isFile(filePath))
64         {
65             throw new FileException("The file not exits!");
66         }
67 
68         this.bufferedArray = (cast(ubyte[]) read(filePath));
69         itor();
70     }
71 
72     public bool readly()
73     {
74         return len(this.buffered) > 0 || len(this.bufferedArray) > 0;
75     }
76 
77     public ubyte[] readRaw()
78     {
79         const int len = len(buffered);
80         ubyte[] bytes = new ubyte[len];
81 
82         for (int i = 0; i < len; i++)
83         {
84             bytes[i] = buffered[i];
85         }
86 
87         itor();
88         return bytes;
89     }
90 
91     public string read()
92     {
93         import std.conv : to;
94         import esstool.stringbuilder;
95 
96         StringBuilder builder = new StringBuilder();
97 
98         foreach (ubyte bt; this.buffered)
99         {
100             builder.append(to!char(bt));
101         }
102 
103         itor();
104         return builder.asString();
105     }
106 
107     /**
108      * Buffed a new line.
109      */
110     private void itor()
111     {
112         if (count(this.bufferedArray) > 0)
113         {
114             this.buffered = new ubyte[0];
115         }
116 
117         import std.container : Array;
118 
119         auto bytes = Array!ubyte();
120         int end = -1;
121 
122         for (int i = 0; i < len(this.bufferedArray); i++)
123         {
124             ubyte bt = this.bufferedArray[i];
125             if (this.bufferedArray[i] == 13)
126             {
127                 end = i;
128                 break;
129             }
130 
131             bytes.insertBack(bt);
132         }
133 
134         if (end == -1)
135         {
136             this.bufferedArray = new ubyte[0];
137         }
138         else
139         {
140             this.bufferedArray = this.bufferedArray[end + 2 .. $];
141         }
142 
143         this.buffered = bytes.data();
144     }
145 }