Fixed Parts{Width, Height}().
[chise/kage.git] / kagecgi / kagetool.c
1 //kagetool.c\r
2 //\r
3 \r
4 #include "kage.h"\r
5 #include "kagecgi.h"\r
6 #include "sysdep.h"\r
7 \r
8 void DotsWidth(int *dlx, int *drx){\r
9         int i, j;\r
10         \r
11     *dlx = 0;\r
12     *drx = 0;\r
13     for(i = 0; i <= pngWidth && *dlx == 0; i++){\r
14                 for(j = 0; j <= pngHeight; j++){\r
15                         if(kageCanvas[j][i] == 0){\r
16                                 *dlx = i;\r
17                                 break;\r
18                         }\r
19                 }\r
20         }\r
21         \r
22         for(i = pngWidth; i >= 0 && *drx == 0; i--){\r
23                 for(j = 0; j <= pngHeight; j++){\r
24                         if(kageCanvas[j][i] == 0){\r
25                                 *drx = i;\r
26                                 break;\r
27                         }\r
28                 }\r
29         }\r
30 }\r
31 \r
32 void DotsHeight(int *dly, int *dry){\r
33     int i, j;\r
34         \r
35     *dly = 0;\r
36         *dry = 0;\r
37     for(j = 0; j <= pngHeight && *dly == 0; j++){\r
38         for(i = 0; i <= pngWidth; i++){\r
39             if(kageCanvas[j][i] == 0){\r
40                 *dly = j;\r
41                 break;\r
42             }\r
43         }\r
44     }\r
45         \r
46     for(j = pngHeight; j >= 0 && *dry == 0; j--){\r
47         for(i = 0; i <= pngWidth; i++){\r
48             if(kageCanvas[j][i] == 0){\r
49                 *dry = j;\r
50                 break;\r
51             }\r
52         }\r
53     }\r
54 }\r
55 \r
56 void PartsWidth(const KGString *in, int *lx, int *rx){\r
57         int tempShotai;\r
58     DrawBox();\r
59     tempShotai = kShotai;\r
60     kShotai = kGothic;\r
61     drawGlyph(in, 1);\r
62     kShotai = tempShotai;\r
63     DotsWidth(lx, rx);\r
64         /*\r
65     int i;\r
66         int *buf, strokes;\r
67         double t, x;\r
68         \r
69         *lx = 1000; *rx = 0;\r
70         buf = convertStroke(in->str, buf, &strokes);\r
71         \r
72     for(i = 0; i < strokes; i++){\r
73                 switch(buf[i * 11 + 0] % 10){\r
74                 \r
75                 case 0:\r
76                 case 9:\r
77                         break;\r
78                 case 1:\r
79                 if(*lx > buf[i * 11 + 3]) *lx = buf[i * 11 + 3];\r
80                         if(*rx < buf[i * 11 + 3]) *rx = buf[i * 11 + 3];\r
81                 if(*lx > buf[i * 11 + 5]) *lx = buf[i * 11 + 5];\r
82                 if(*rx < buf[i * 11 + 5]) *rx = buf[i * 11 + 5];\r
83                         break;\r
84                 case 2:\r
85                         for(t = 0; t <= 1; t = t + 0.05){\r
86                                 x = (1.0 - t) * (1.0 - t) * buf[i * 11 + 3] + 2.0 * t * (1.0 - t) * buf[i * 11 + 5] + t * t * buf[i * 11 + 7];\r
87                         if(*lx > x) *lx = x;\r
88                     if(*rx < x) *rx = x;\r
89                         }\r
90                         break;\r
91                 case 3:\r
92                 if(*lx > buf[i * 11 + 3]) *lx = buf[i * 11 + 3];\r
93                         if(*rx < buf[i * 11 + 3]) *rx = buf[i * 11 + 3];\r
94                 if(*lx > buf[i * 11 + 5]) *lx = buf[i * 11 + 5];\r
95                 if(*rx < buf[i * 11 + 5]) *rx = buf[i * 11 + 5];\r
96                 if(*lx > buf[i * 11 + 7]) *lx = buf[i * 11 + 7];\r
97             if(*rx < buf[i * 11 + 7]) *rx = buf[i * 11 + 7];\r
98                         break;\r
99                 case 6:\r
100                         for(t = 0; t < 1; t = t + 0.05){\r
101                                 x = (1.0 - t) * (1.0 - t) * (1.0 - t) * buf[i * 11 + 3] + 3.0 * t * (1.0 - t) * (1.0 - t) * buf[i * 11 + 5] + 3 * t * t * (1.0 - t) * buf[i * 11 + 7] + t * t * t * buf[i * 11 + 9];\r
102                         if(*lx > x) *lx = x;\r
103                     if(*rx < x) *rx = x;\r
104                         }\r
105                         break;\r
106                 case 7:\r
107                 if(*lx > buf[i * 11 + 3]) *lx = buf[i * 11 + 3];\r
108                         if(*rx < buf[i * 11 + 3]) *rx = buf[i * 11 + 3];\r
109                         for(t = 0; t < 1; t = t + 0.05){\r
110                                 x = (1.0 - t) * (1.0 - t) * buf[i * 11 + 5] + 2.0 * t * (1.0 - t) * buf[i * 11 + 7] + t * t * buf[i * 11 + 9];\r
111                         if(*lx > x) *lx = x;\r
112                     if(*rx < x) *rx = x;\r
113                         }\r
114                 }\r
115         }\r
116         free(buf);\r
117         */\r
118 }\r
119 \r
120 void PartsHeight(const KGString *in, int *ly, int *ry){\r
121         int tempShotai;\r
122     DrawBox();\r
123     tempShotai = kShotai;\r
124     kShotai = kGothic;\r
125     drawGlyph(in, 1);\r
126     kShotai = tempShotai;\r
127     DotsHeight(ly, ry);\r
128         /*\r
129     int i;\r
130         int *buf, strokes;\r
131         double t, y;\r
132         \r
133         *ly = 1000; *ry = 0;\r
134         buf = convertStroke(in->str, buf, &strokes);\r
135         \r
136     for(i = 0; i < strokes; i++){\r
137                 switch(buf[i * 11 + 0] % 10){\r
138                 \r
139                 case 0:\r
140                 case 9:\r
141                         break;\r
142                 case 1:\r
143                 if(*ly > buf[i * 11 + 4]) *ly = buf[i * 11 + 4];\r
144                         if(*ry < buf[i * 11 + 4]) *ry = buf[i * 11 + 4];\r
145                 if(*ly > buf[i * 11 + 6]) *ly = buf[i * 11 + 6];\r
146                 if(*ry < buf[i * 11 + 6]) *ry = buf[i * 11 + 6];\r
147                         break;\r
148                 case 2:\r
149                         for(t = 0; t <= 1; t = t + 0.05){\r
150                                 y = (1.0 - t) * (1.0 - t) * buf[i * 11 + 4] + 2.0 * t * (1.0 - t) * buf[i * 11 + 6] + t * t * buf[i * 11 + 8];\r
151                         if(*ly > y) *ly = y;\r
152                     if(*ry < y) *ry = y;\r
153                         }\r
154                         break;\r
155                 case 3:\r
156                 if(*ly > buf[i * 11 + 4]) *ly = buf[i * 11 + 4];\r
157                         if(*ry < buf[i * 11 + 4]) *ry = buf[i * 11 + 4];\r
158                 if(*ly > buf[i * 11 + 6]) *ly = buf[i * 11 + 6];\r
159                 if(*ry < buf[i * 11 + 6]) *ry = buf[i * 11 + 6];\r
160                 if(*ly > buf[i * 11 + 8]) *ly = buf[i * 11 + 8];\r
161             if(*ry < buf[i * 11 + 8]) *ry = buf[i * 11 + 8];\r
162                         break;\r
163                 case 6:\r
164                         for(t = 0; t < 1; t = t + 0.05){\r
165                                 y = (1.0 - t) * (1.0 - t) * (1.0 - t) * buf[i * 11 + 4] + 3.0 * t * (1.0 - t) * (1.0 - t) * buf[i * 11 + 6] + 3 * t * t * (1.0 - t) * buf[i * 11 + 8] + t * t * t * buf[i * 11 + 10];\r
166                         if(*ly > y) *ly = y;\r
167                     if(*ry < y) *ry = y;\r
168                         }\r
169                         break;\r
170                 case 7:\r
171                 if(*ly > buf[i * 11 + 4]) *ly = buf[i * 11 + 4];\r
172                         if(*ry < buf[i * 11 + 4]) *ry = buf[i * 11 + 4];\r
173                         for(t = 0; t < 1; t = t + 0.05){\r
174                                 y = (1.0 - t) * (1.0 - t) * buf[i * 11 + 6] + 2.0 * t * (1.0 - t) * buf[i * 11 + 8] + t * t * buf[i * 11 + 10];\r
175                         if(*ly > y) *ly = y;\r
176                     if(*ry < y) *ry = y;\r
177                         }\r
178                 }\r
179         }\r
180         free(buf);\r
181         */\r
182         /*\r
183     int i;\r
184         int *buf, strokes;\r
185         \r
186         buf = convertStroke(in->str, buf, &strokes);\r
187         *ly = 1000; *ry = 0;\r
188         \r
189     for(i = 0; i < strokes; i++){\r
190         if(buf[i * 11 + 0] % 10 == 0) continue;\r
191                 \r
192         if(*ly > buf[i * 11 + 4]) *ly = buf[i * 11 + 4];\r
193                 if(*ry < buf[i * 11 + 4]) *ry = buf[i * 11 + 4];\r
194         if(*ly > buf[i * 11 + 6]) *ly = buf[i * 11 + 6];\r
195         if(*ry < buf[i * 11 + 6]) *ry = buf[i * 11 + 6];\r
196                 \r
197         if(buf[i * 11 + 0] % 10 == 2 || buf[i * 11 + 0] % 10 == 3 || buf[i * 11 + 0] % 10 == 8){\r
198                 if(*ly > buf[i * 11 + 8]) *ly = buf[i * 11 + 8];\r
199             if(*ry < buf[i * 11 + 8]) *ry = buf[i * 11 + 8];\r
200                 }\r
201         if(buf[i * 11 + 0] % 10 == 4 || buf[i * 11 + 0] % 10 == 6 || buf[i * 11 + 0] % 10 == 7){\r
202                 if(*ly > buf[i * 11 + 10]) *ly = buf[i * 11 + 10];\r
203                 if(*ry < buf[i * 11 + 10]) *ry = buf[i * 11 + 10];\r
204         }\r
205         }\r
206         free(buf);\r
207         */\r
208 }\r
209 \r
210 KGString * CalcSizes(const KGString *in, int mode){\r
211     int i, j, k, basewidth, one_lineX, one_lineY;\r
212     int dlx1, drx1, dly1, dry1;\r
213         int px1, py1;\r
214     double pr1, pry1;\r
215         \r
216     int mitsuT, flg_boxT, widthT, heightT;\r
217     double tateT, yokoT;\r
218     int cutx, cuty;\r
219         \r
220         int *buf, strokes;\r
221         int tf[12];\r
222         KGString *out;\r
223         \r
224         out = kg_string_new("");\r
225     basewidth = pngWidth * 0.9;\r
226         \r
227     if(mode == 0){\r
228         //temporary adjustment X-axis\r
229         PartsWidth(in, &dlx1, &drx1);\r
230         if(dlx1 == drx1){\r
231             pr1 = 1.0;\r
232             px1 = pngWidth / 2 - dlx1;\r
233             one_lineX = 1;\r
234         }\r
235         else{\r
236             pr1 = (double)basewidth/(drx1 - dlx1);\r
237             px1 = (pngWidth-basewidth)/2 - (double)(dlx1 * pr1);\r
238             one_lineX = 0;\r
239         }\r
240                 \r
241         //temporary adjustment Y-axis\r
242         PartsHeight(in, &dly1, &dry1);\r
243         if(dly1 == dry1){\r
244             pry1 = 1.0;\r
245             py1 = pngWidth / 2 - dly1;\r
246             one_lineY = 1;\r
247         }\r
248                 else{\r
249             pry1 = (double)basewidth/(dry1 - dly1);\r
250             py1 = (pngWidth-basewidth)/2 - (double)(dly1 * pry1);\r
251             one_lineY = 0;\r
252         }\r
253     }\r
254         else{\r
255         PartsWidth(in, &dlx1, &drx1);\r
256         PartsHeight(in, &dly1, &dry1);\r
257                 \r
258         cutx = 0;\r
259         cuty = 0;\r
260                 \r
261         CalcOptions(in, &mitsuT, &flg_boxT, &yokoT, &tateT);\r
262                 \r
263         widthT = basewidth;\r
264         heightT = basewidth;\r
265                 \r
266         if(flg_boxT % 2 / 1 != 0){\r
267             widthT = widthT - kWidth * 3;\r
268             cutx++;\r
269         }\r
270         if(flg_boxT % 4 / 2 != 0){\r
271             widthT = widthT - kWidth * 3;\r
272             cutx++;\r
273         }\r
274         if(flg_boxT % 8 / 4 != 0){\r
275             heightT = heightT - kWidth * 3;\r
276             cuty++;\r
277         }\r
278         if(flg_boxT % 16 / 8 != 0){\r
279             heightT = heightT - kWidth * 3;\r
280             cuty++;\r
281         }\r
282                 \r
283         //especially get small the 'mouth'\r
284         if(mode == 2 && flg_boxT % 16 == 15){\r
285             widthT = widthT - kWidth * (max(0, 16 - (int)yokoT * 4));\r
286             heightT = heightT - kWidth * (max(0, 16 - (int)tateT * 4));\r
287                 }\r
288         //'dot' as same as 'mouth'\r
289         if(mode == 2 && tateT == 1 && yokoT == 1){\r
290             widthT = pngWidth * 0.9 * 0.5;\r
291             heightT = pngWidth * 0.9 * 0.5;\r
292         }\r
293                 \r
294                 if(flg_boxT % 64 / 32 != 0){\r
295                         buf = convertStroke(in->str, buf, &strokes);\r
296                         for(i = 0; i < strokes; i++){\r
297                 if(buf[i * 11 + 0] == 0) j = buf[i * 11 + 4];// j : center line\r
298             }\r
299             free(buf);\r
300             k = max(j - dlx1, drx1 - j);// k : distance from center line\r
301             pr1 = (basewidth * 0.5) / k;\r
302                         \r
303             if(k == j - dlx1) px1 = 0;\r
304             else px1 = pngWidth * 0.5 - j * pr1;\r
305         }\r
306         else if(dlx1 == drx1){\r
307             pr1 = 1.0;\r
308             px1 = pngWidth / 2 - dlx1;\r
309         }\r
310         else{\r
311             pr1 = (double)widthT/(drx1 - dlx1);\r
312             px1 = pngWidth / 2 - (double)((dlx1 + drx1) / 2 * pr1);\r
313             if(flg_boxT % 2 / 1 != 0 && flg_boxT % 4 / 2 == 0) px1 = px1 + kWidth * 1.5;\r
314             if(flg_boxT % 2 / 1 == 0 && flg_boxT % 4 / 2 != 0) px1 = px1 - kWidth * 1.5;\r
315         }\r
316                 \r
317         if(dly1 == dry1){\r
318             pry1 = 1.0;\r
319             py1 = pngWidth / 2 - dly1;\r
320         }\r
321         else{\r
322             pry1 = (double)heightT/(dry1 - dly1);\r
323             py1 = pngWidth / 2 - (double)((dly1 + dry1) / 2 * pry1);\r
324             if(flg_boxT % 8 / 4 != 0 && flg_boxT % 16 / 8 == 0) py1 = py1 + kWidth * 1.5;\r
325             if(flg_boxT % 8 / 4 == 0 && flg_boxT % 16 / 8 != 0) py1 = py1 - kWidth * 1.5;\r
326         }\r
327         }\r
328         \r
329         //generate result\r
330         tf[0] = px1;\r
331         tf[1] = py1;\r
332         tf[2] = px1 + pr1 * 200;\r
333         tf[3] = py1 + pry1 * 200;\r
334         addStrokeWithTransform(in, 1, tf, out, 0);\r
335         return kg_string_new(out->str);\r
336 }\r
337 \r
338 void DrawBox(){\r
339         int i, j;\r
340         \r
341         for(i = 0; i < canvasWidth; i++){\r
342                 for(j = 0; j < canvasHeight; j++){\r
343                         kageCanvas[j][i] = 0xFF;\r
344                 }\r
345         }\r
346 }\r
347 \r
348 void CalcOptions(const KGString *in, int *mitsudo, int *flag, double *yoko, double *tate){\r
349     int i, j, k, l, flg;\r
350     int dlx1, drx1, dly1, dry1;\r
351     int kari, mode;\r
352         int tempShotai;\r
353         int *buf, strokes;\r
354         \r
355     *flag = 0;\r
356         \r
357     DrawBox();\r
358     tempShotai = kShotai;\r
359     kShotai = kGothic;\r
360     drawGlyph(in, 1);\r
361     kShotai = tempShotai;\r
362     DotsWidth(&dlx1, &drx1);\r
363     DotsHeight(&dly1, &dry1);\r
364         \r
365         //check left side\r
366     k = 0;\r
367     l = 0;\r
368     for(i = 0; i < pngWidth; i++){\r
369         flg = 0;\r
370         for(j = 0; j < kWidth; j++){\r
371             if(kageCanvas[i][dlx1 + j] == 0) flg = 1;\r
372         }\r
373         if(flg == 1){\r
374                 k++;\r
375         }\r
376         else{\r
377             if(k > l) l = k;\r
378             k = 0;\r
379         }\r
380     }\r
381     if(k > l) l = k;\r
382     \r
383     if(l > pngWidth * 0.9 / 4) *flag = *flag | 1;\r
384         \r
385     //check right side\r
386     k = 0;\r
387     l = 0;\r
388     for(i = 0; i < pngWidth; i++){\r
389         flg = 0;\r
390         for(j = 0; j < kWidth; j++){\r
391             if(kageCanvas[i][drx1 - j] == 0) flg = 1;\r
392         }\r
393         if(flg == 1) k++;\r
394         else{\r
395             if(k > l) l = k;\r
396             k = 0;\r
397         }\r
398     }\r
399     if(k > l) l = k;\r
400         \r
401     if(l > pngWidth * 0.9 / 4) *flag = *flag | 2;\r
402         \r
403     //check upper side\r
404     k = 0;\r
405     l = 0;\r
406     for(i = 0; i < pngWidth; i++){\r
407         flg = 0;\r
408                 for(j = 0; j < kWidth; j++){\r
409             if(kageCanvas[dly1 + j][i] == 0) flg = 1;\r
410         }\r
411         if(flg == 1) k++;\r
412         else{\r
413             if(k > l) l = k;\r
414             k = 0;\r
415         }\r
416     }\r
417     if(k > l) l = k;\r
418         \r
419     if(l > pngWidth * 0.9 / 4) *flag = *flag | 4;\r
420         \r
421     //check bottom side\r
422     k = 0;\r
423     l = 0;\r
424     for(i = 0; i < pngWidth; i++){\r
425         flg = 0;\r
426         for(j = 0; j < kWidth; j++){\r
427             if(kageCanvas[dry1 - j][i] == 0) flg = 1;\r
428         }\r
429         if(flg == 1) k++;\r
430         else{\r
431             if(k > l) l = k;\r
432             k = 0;\r
433         }\r
434     }\r
435     if(k > l) l = k;\r
436         \r
437     if(l > pngWidth * 0.9 / 4) *flag = *flag | 8;\r
438         \r
439     //count black dots\r
440     *mitsudo = 0;\r
441     for(i = 0; i < pngHeight; i++){\r
442         for(j = 0; j < pngWidth; j++){\r
443             if(kageCanvas[i][j] == 0) *mitsudo += 1;\r
444         }\r
445     }\r
446         \r
447     //calculate X-axis complexity\r
448     *yoko = 0;\r
449     for(i = dly1; i <= dry1; i++){\r
450         mode = 0;\r
451         kari = 0;\r
452         for(j = dlx1; j <= drx1; j++){\r
453                         if(kageCanvas[i][j] == 0 &&\r
454              kageCanvas[i][j+1] == 0 &&\r
455              kageCanvas[i][j+2] == 0){\r
456                 if(mode == 0){\r
457                     mode = 1;\r
458                     kari++;\r
459                 }\r
460             }\r
461             else if(mode == 1) mode = 0;\r
462         }\r
463         if(kari > *yoko) *yoko = kari;\r
464     }\r
465         \r
466     //calculate Y-axis complexity\r
467     *tate = 0;\r
468     for(i = dlx1; i <= drx1; i++){\r
469         mode = 0;\r
470         kari = 0;\r
471         for(j = dly1; j <= dry1; j++){\r
472             if(kageCanvas[j][i] == 0 &&\r
473              kageCanvas[j+1][i] == 0 &&\r
474              kageCanvas[j+2][i] == 0){\r
475                 if(mode == 0){\r
476                     mode = 1;\r
477                     kari++;\r
478                 }\r
479             }\r
480             else if(mode == 1) mode = 0;\r
481         }\r
482         if(kari > *tate) *tate = kari;\r
483     }\r
484         \r
485     //use user defined option if it exists\r
486         buf = convertStroke(in->str, buf, &strokes);\r
487         for(i = 0; i < strokes; i++){\r
488         if(buf[i * 11 + 0] % 10 == 0){\r
489             if(buf[i * 11 + 1] != 0) *yoko = (double)(buf[i * 11 + 1]) * 0.1;\r
490             if(buf[i * 11 + 2] != 0) *tate = (double)(buf[i * 11 + 2]) * 0.1;\r
491             if(buf[i * 11 + 3] != 0) *flag = *flag + buf[i * 11 + 3] * 16;\r
492         }\r
493     }\r
494     free(buf);\r
495 }\r
496 \r
497 void DoDrawParts(const KGString *in, const int lx1, const double rf1, const int ly1, const double rfy1){\r
498     int i;\r
499         int *buf, strokes;\r
500         \r
501     DrawBox();\r
502         buf = convertStroke(in->str, buf, &strokes);\r
503         for(i = 0; i < strokes; i++){\r
504                 dfDrawFont(buf[i * 11 + 0],\r
505                  buf[i * 11 + 1],\r
506                  buf[i * 11 + 2],\r
507                  buf[i * 11 + 3] * rf1 + lx1,\r
508                  buf[i * 11 + 4] * rfy1 + ly1,\r
509                  buf[i * 11 + 5] * rf1 + lx1,\r
510                  buf[i * 11 + 6] * rfy1 + ly1,\r
511                  buf[i * 11 + 7] * rf1 + lx1,\r
512                  buf[i * 11 + 8] * rfy1 + ly1,\r
513                  buf[i * 11 + 9] * rf1 + lx1,\r
514                  buf[i * 11 + 10] * rfy1 + ly1);\r
515     }\r
516         free(buf);\r
517 }\r
518 \r
519 void DoDrawMixFont(const KGString *in1,\r
520  const int lx1,\r
521  const double rf1,\r
522  const KGString *in2,\r
523  const int lx2,\r
524  const double rf2,\r
525  const int ly1,\r
526  const double rfy1,\r
527  const int ly2,\r
528  const double rfy2){\r
529     int i;\r
530         int *buf, strokes;\r
531         \r
532         DrawBox();\r
533         buf = convertStroke(in1->str, buf, &strokes);\r
534         for(i = 0; i < strokes; i++){\r
535                 dfDrawFont(buf[i * 11 + 0],\r
536                  buf[i * 11 + 1],\r
537                  buf[i * 11 + 2],\r
538                  buf[i * 11 + 3] * rf1 + lx1,\r
539                  buf[i * 11 + 4] * rfy1 + ly1,\r
540                  buf[i * 11 + 5] * rf1 + lx1,\r
541                  buf[i * 11 + 6] * rfy1 + ly1,\r
542                  buf[i * 11 + 7] * rf1 + lx1,\r
543                  buf[i * 11 + 8] * rfy1 + ly1,\r
544                  buf[i * 11 + 9] * rf1 + lx1,\r
545                  buf[i * 11 + 10] * rfy1 + ly1);\r
546     }\r
547         free(buf);\r
548         \r
549         buf = convertStroke(in2->str, buf, &strokes);\r
550         for(i = 0; i < strokes; i++){\r
551                 dfDrawFont(buf[i * 11 + 0],\r
552                  buf[i * 11 + 1],\r
553                  buf[i * 11 + 2],\r
554                  buf[i * 11 + 3] * rf2 + lx2,\r
555                  buf[i * 11 + 4] * rfy2 + ly2,\r
556                  buf[i * 11 + 5] * rf2 + lx2,\r
557                  buf[i * 11 + 6] * rfy2 + ly2,\r
558                  buf[i * 11 + 7] * rf2 + lx2,\r
559                  buf[i * 11 + 8] * rfy2 + ly2,\r
560                  buf[i * 11 + 9] * rf2 + lx2,\r
561                  buf[i * 11 + 10] * rfy2 + ly2);\r
562     }\r
563         free(buf);\r
564 }\r
565 \r