1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2007, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexander Krivonogov ( algen )
11 *
12 ******************************************************************************/
13
14 /*-----------------------------------------------------------------------------
15 * Id: csv L "CSV"
16 *
17 * Summary: Working with CSV data. Variables of the #b(csv) type allow you to
18 work with data in the csv format.#p[
19 #b('string1_1,"string1_2",string1_3#br#
20 string2_1,"string2_2",string2_3')]
21 The #b(csv) type is inherited from #b(str) type. So, you can use
22 #a(string, string methods and operators).
23 For using this library, it is required to specify the file
24 csv.g (from lib\csv subfolder) with include command. #srcg[
25 |include : $"...\gentee\lib\csv\csv.g"]
26 *
27 * List: *#lng/opers#,csv_opfor,
28 *#lng/methods#,csv_append,csv_clear,csv_read,csv_settings,csv_write
29 *
30 -----------------------------------------------------------------------------*/
31
32 type csvfordata <inherit=fordata>
33 {
34 arrstr lst
35 uint flgeof
36 }
37
38 type csv <inherit=str index=arrstr> //Основная структура csv
39 {
40 byte csepar //Символ разделитель, по умолчанию ;
41 byte copen //Символ начала элемента, по умолчанию "
42 byte cclose //Символ конца элемента, по умолчанию "
43 }
44
45 method csv csv.init()
46 {
47 this.copen = this.cclose = '"'
48 this.csepar = ','
49 return this
50 }
51
52 /*-----------------------------------------------------------------------------
53 * Id: csv_settings F2
54 *
55 * Summary: Set separating and limiting characters for csv data.
56 *
57 * Params: separ - Separator. Comma by default.
58 open - The left limiting character. Double quotes by default.
59 close - The right limiting character. Double quotes by default.
60 *
61 -----------------------------------------------------------------------------*/
62
63 method csv.settings( uint separ, uint open, uint close )
64 {
65 this.csepar = separ
66 this.copen = open
67 this.cclose = close
68 }
69
70 define //Флаги текущего состояния
71 {
72 CSVP_OPEN = 0x01
73 CSVP_READ = 0x02
74 CSVP_LASTCLOSE = 0x04
75 CSVP_LASTR = 0x08
76 CSVP_ENDITEM = 0x10
77 CSVP_ENDLINE = 0x20
78 CSVP_NOADD = 0x40
79 }
80
81 method uint csv.proc( csvfordata fd )
82 {
83 byte c
84 uint i
85 uint flg
86 i = 0
87
88 if fd.icur >= *this : return 1
89 while 1
90 {
91 if !flg
92 {
93 if i >= *fd.lst : fd.lst.expand( 5 )
94 fd.lst[i].clear()
95 }
96 if fd.icur < *this->str
97 {
98 c = this->str[fd.icur++]
99 if !flg && c == this.copen : flg = $CSVP_READ | $CSVP_OPEN | $CSVP_NOADD
100 else
101 {
102 switch c
103 {
104 case this.cclose
105 {
106 if flg & $CSVP_LASTCLOSE : flg &= ~$CSVP_LASTCLOSE
107 else : flg |= $CSVP_LASTCLOSE | $CSVP_NOADD
108 }
109 case this.csepar
110 {
111 if !(flg & $CSVP_OPEN) || flg & $CSVP_LASTCLOSE
112 {
113 flg |= $CSVP_ENDITEM | $CSVP_NOADD
114 }
115 }
116 case 0x0A
117 {
118 if !(flg & $CSVP_OPEN) || flg & $CSVP_LASTCLOSE
119 {
120 flg |= $CSVP_ENDITEM | $CSVP_NOADD | $CSVP_ENDLINE
121 }
122 }
123 case 0x0D
124 {
125 if !(flg & $CSVP_OPEN) || flg & $CSVP_LASTCLOSE
126 {
127 flg |= $CSVP_ENDITEM | $CSVP_NOADD | $CSVP_ENDLINE | $CSVP_LASTR
128 }
129 }
130 default
131 {
132 if flg & $CSVP_LASTCLOSE
133 {
134 fd.lst[i].appendch( this.cclose )
135 flg &= ~$CSVP_LASTCLOSE
136 }
137 }
138 }
139 }
140 }
141 else
142 {
143 flg |= $CSVP_NOADD | $CSVP_ENDITEM | $CSVP_ENDLINE
144 }
145 if !flg: flg = $CSVP_READ
146
147 if flg & $CSVP_NOADD : flg &= ~$CSVP_NOADD
148 else : fd.lst[i].appendch( c )
149 if flg & $CSVP_ENDITEM
150 {
151 i++
152 if flg & $CSVP_ENDLINE
153 {
154 if !(flg & $CSVP_OPEN) && flg & $CSVP_LASTCLOSE
155 {
156 fd.lst[i].appendch( this.cclose )
157 }
158 if flg & $CSVP_LASTR &&
159 fd.icur < *this->str &&
160 this->str[fd.icur] == 0x0A : fd.icur++
161 break
162 }
163 flg = 0
164 }
165
166 }
167 fd.lst.cut( i )
168 return 0
169 }
170
171 /*-----------------------------------------------------------------------------
172 * Id: csv_opfor F5
173 *
174 * Summary: Foreach operator. Looking through all items with the help of the
175 #b(foreach) operator. An element in an object of the #b(csv) type
176 is an array of strings #b(arrstr). Each string is split into
177 separate elements by the separator and these elements are
178 written into the passed array.#srcg[
179 |csv mycsv
180 |uint i k
181 |...
182 |foreach item, mycsv
183 |{
184 | print( "Item: \(++i)\n" )
185 | fornum k = 0, *item
186 | {
187 | print( "\(item[k])\n")
188 | }
189 |}]
190 *
191 * Title: foreach var,csv
192 *
193 * Define: foreach variable,csv {...}
194 *
195 -----------------------------------------------------------------------------*/
196
197 method uint csv.next( csvfordata fd )
198 {
199 fd.flgeof = this.proc( fd )
200 return &fd.lst
201 }
202
203 method uint csv.first( csvfordata fd )
204 {
205 fd.icur = 0
206 fd.flgeof = this.proc( fd )
207 return &fd.lst
208 }
209
210 method uint csv.eof( csvfordata fd )
211 {
212 return fd.flgeof
213 }
214
215 /*-----------------------------------------------------------------------------
216 * Id: csv_append F2
217 *
218 * Summary: Adds a string to a csv object.
219 *
220 * Params: arrs - The array of strings containing the elements of a string. /
221 All strings will be combined into one record and added to /
222 the #b(csv) object.
223 *
224 -----------------------------------------------------------------------------*/
225
226 method csv.append( arrstr arrs )
227 {
228 uint i, j
229
230 fornum i=0, *arrs
231 {
232 if i : this->str.appendch( this.csepar )
233 this->str.appendch( this.copen )
234 fornum j=0, *arrs[i]
235 {
236 this->str.appendch( (arrs[i])[j] )
237 if (arrs[i])[j] == this.cclose
238 {
239 this->str.appendch( (arrs[i])[j] )
240 }
241 }
242 this->str.appendch( this.cclose )
243 }
244 this->str += "\l"
245 }
246
247 /*-----------------------------------------------------------------------------
248 * Id: csv_read F2
249 *
250 * Summary: Read data from a csv file.
251 *
252 * Params: filename - Filename.
253 *
254 * Return: The size of the read data.
255 *
256 * Define: method uint csv.read( str filename )
257 *
258 -----------------------------------------------------------------------------*/
259
260 /*-----------------------------------------------------------------------------
261 * Id: csv_write F2
262 *
263 * Summary: Writing csv data to a file.
264 *
265 * Params: filename - The name of the file for writing. If the file already /
266 exists, it will be overwritten.
267 *
268 * Return: The size of the written data.
269 *
270 * Define: method uint csv.write( str filename )
271 *
272 -----------------------------------------------------------------------------*/
273
274 /*-----------------------------------------------------------------------------
275 ** Id: csv_clear F3
276 *
277 * Summary: Clear the csv data object.
278 *
279 * Define: method uint csv.clear()
280 *
281 -----------------------------------------------------------------------------*/
282
283 //-----------------------------------------------------------------------------
284