1 /*
2  * E-UAE - The portable Amiga Emulator
3  *
4  * Generate pixel output code.
5  *
6  * (c) 2006 Richard Drummond
7  * (c) 2013 Sven Eden
8  */
9 
10 #include <stdlib.h>
11 #include <stdarg.h>
12 #include <stdio.h>
13 
14 /* Output for big-endian target if true, little-endian is false. */
15 int do_bigendian;
16 
17 typedef int DEPTH_T;
18 
19 #define DEPTH_8BPP 0
20 #define DEPTH_16BPP 1
21 #define DEPTH_32BPP 2
22 #define DEPTH_MAX DEPTH_32BPP
23 
get_depth_str(DEPTH_T bpp)24 static const char *get_depth_str (DEPTH_T bpp)
25 {
26 	if (bpp == DEPTH_8BPP)
27 		return "8";
28 	else if (bpp == DEPTH_16BPP)
29 		return "16";
30 	else
31 		return "32";
32 }
33 
get_depth_type_str(DEPTH_T bpp)34 static const char *get_depth_type_str (DEPTH_T bpp)
35 {
36 	if (bpp == DEPTH_8BPP)
37 		return "uae_u8";
38 	else if (bpp == DEPTH_16BPP)
39 		return "uae_u16";
40 	else
41 		return "uae_u32";
42 }
43 
44 typedef int HMODE_T;
45 
46 #define HMODE_NORMAL	0
47 #define HMODE_DOUBLE	1
48 #define HMODE_DOUBLE2X	2
49 #define HMODE_HALVE1	3
50 #define HMODE_HALVE1F	4
51 #define HMODE_HALVE2	5
52 #define HMODE_HALVE2F	6
53 #define HMODE_MAX HMODE_HALVE2F
54 
get_hmode_str(HMODE_T hmode)55 static const char *get_hmode_str (HMODE_T hmode)
56 {
57 	if (hmode == HMODE_DOUBLE)
58 		return "_stretch1";
59 	else if (hmode == HMODE_DOUBLE2X)
60 		return "_stretch2";
61 	else if (hmode == HMODE_HALVE1)
62 		return "_shrink1";
63 	else if (hmode == HMODE_HALVE1F)
64 		return "_shrink1f";
65 	else if (hmode == HMODE_HALVE2)
66 		return "_shrink2";
67 	else if (hmode == HMODE_HALVE2F)
68 		return "_shrink2f";
69 	else
70 		return "";
71 }
72 
73 
74 typedef enum
75 {
76 	CMODE_NORMAL,
77 	CMODE_DUALPF,
78 	CMODE_EXTRAHB,
79 	CMODE_HAM
80 } CMODE_T;
81 #define CMODE_MAX CMODE_HAM
82 
83 
84 static FILE *outfile;
85 static unsigned int outfile_indent = 0;
86 
set_outfile(FILE * f)87 void set_outfile (FILE *f)
88 {
89 	outfile = f;
90 }
91 
set_indent(int indent)92 int set_indent (int indent)
93 {
94 	int old_indent = outfile_indent;
95 	outfile_indent = indent;
96 	return old_indent;
97 }
98 
outln(const char * s)99 void outln (const char *s)
100 {
101 	unsigned int i;
102 	for (i = 0; i < outfile_indent; i++)
103 		fputc (' ', outfile);
104 	fprintf (outfile, "%s\n", s);
105 }
106 
outlnf(const char * s,...)107 void outlnf (const char *s, ...)
108 {
109 	va_list ap;
110 	unsigned int i;
111 	for (i = 0; i < outfile_indent; i++)
112 		fputc (' ', outfile);
113 	va_start (ap, s);
114 	vfprintf (outfile, s, ap);
115 	fputc ('\n', outfile);
116 }
117 
out_linetoscr_decl(DEPTH_T bpp,HMODE_T hmode,int aga,int spr)118 static void out_linetoscr_decl (DEPTH_T bpp, HMODE_T hmode, int aga, int spr)
119 {
120 	outlnf ("static int NOINLINE linetoscr_%s%s%s%s (int spix, int dpix, int dpix_end)",
121 		get_depth_str (bpp),
122 		get_hmode_str (hmode), aga ? "_aga" : "", spr ? "_spr" : "");
123 }
124 
out_linetoscr_do_srcpix(DEPTH_T bpp,HMODE_T hmode,int aga,CMODE_T cmode,int spr)125 static void out_linetoscr_do_srcpix (DEPTH_T bpp, HMODE_T hmode, int aga, CMODE_T cmode, int spr)
126 {
127 	if (aga && cmode != CMODE_DUALPF) {
128 		if (spr)
129 			outln (	"    sprpix_val = pixdata.apixels[spix];");
130 		if (CMODE_HAM != cmode)
131 			outln (	"    spix_val = pixdata.apixels[spix] ^ xor_val;");
132 	} else if (cmode != CMODE_HAM) {
133 		outln (		"    spix_val = pixdata.apixels[spix];");
134 		if (spr) {
135 			outln (	"    sprpix_val = spix_val;");
136 		}
137 	}
138 }
139 
out_linetoscr_do_dstpix(DEPTH_T bpp,HMODE_T hmode,int aga,CMODE_T cmode,int spr)140 static void out_linetoscr_do_dstpix (DEPTH_T bpp, HMODE_T hmode, int aga, CMODE_T cmode, int spr)
141 {
142 	if (aga && cmode == CMODE_HAM) {
143 		outln (	    "    spix_val = ham_linebuf[spix];");
144 		outln (	    "    dpix_val = CONVERT_RGB (spix_val);");
145 	} else if (cmode == CMODE_HAM) {
146 		outln (		"    spix_val = ham_linebuf[spix];");
147 		outln ( "    dpix_val = xcolors[spix_val];");
148 		if (spr)
149 			outln ( "    sprpix_val = pixdata.apixels[spix];");
150 	} else if (aga && cmode == CMODE_DUALPF) {
151 		outln (		"    {");
152 		outln (		"        uae_u8 val = lookup[spix_val];");
153 		outln (		"        if (lookup_no[spix_val])");
154 		outln (		"            val += dblpfofs[bpldualpf2of];");
155 		outln (		"        val ^= xor_val;");
156 		outln (		"        dpix_val = colors_for_drawing.acolors[val];");
157 		outln (		"    }");
158 	} else if (cmode == CMODE_DUALPF) {
159 		outln (		"    dpix_val = colors_for_drawing.acolors[lookup[spix_val]];");
160 	} else if (aga && cmode == CMODE_EXTRAHB) {
161 		outln (		"    if (spix_val >= 32 && spix_val < 64) {");
162 		outln (		"        unsigned int c = (colors_for_drawing.color_regs_aga[spix_val - 32] >> 1) & 0x7F7F7F;");
163 		outln (		"        dpix_val = CONVERT_RGB (c);");
164 		outln (		"    } else");
165 		outln (		"        dpix_val = colors_for_drawing.acolors[spix_val];");
166 	} else if (cmode == CMODE_EXTRAHB) {
167 		outln (		"    if (spix_val <= 31)");
168 		outln (		"        dpix_val = colors_for_drawing.acolors[spix_val];");
169 		outln (		"    else");
170 		outln (		"        dpix_val = xcolors[(colors_for_drawing.color_regs_ecs[spix_val - 32] >> 1) & 0x777];");
171 	} else
172 		outln (		"    dpix_val = colors_for_drawing.acolors[spix_val];");
173 }
174 
out_linetoscr_do_incspix(DEPTH_T bpp,HMODE_T hmode,int aga,CMODE_T cmode,int spr)175 static void out_linetoscr_do_incspix (DEPTH_T bpp, HMODE_T hmode, int aga, CMODE_T cmode, int spr)
176 {
177 	if (hmode == HMODE_HALVE1F) {
178 		outln (         "    {");
179 		outln (         "    uae_u32 tmp_val = dpix_val;");
180 		outln (		"    spix++;");
181 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
182 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
183 		outlnf (	"    dpix_val = merge_2pixel%d (dpix_val, tmp_val);", bpp == 0 ? 8 : bpp == 1 ? 16 : 32);
184 		outln (		"    spix++;");
185 		outln (         "    }");
186 	} else if (hmode == HMODE_HALVE2F) {
187 		outln (         "    {");
188 		outln (         "    uae_u32 tmp_val = dpix_val, tmp_val2, tmp_val3;");
189 		outln (		"    spix++;");
190 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
191 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
192 		outln (		"    spix++;");
193 		outln (		"    tmp_val2 = dpix_val;");
194 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
195 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
196 		outln (		"    spix++;");
197 		outln (		"    tmp_val3 = dpix_val;");
198 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
199 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
200 		outlnf (        "    tmp_val = merge_2pixel%d (tmp_val, tmp_val2);", bpp == 0 ? 8 : bpp == 1 ? 16 : 32);
201 		outlnf (        "    tmp_val2 = merge_2pixel%d (tmp_val3, dpix_val);", bpp == 0 ? 8 : bpp == 1 ? 16 : 32);
202 		outlnf (	"    dpix_val = merge_2pixel%d (tmp_val, tmp_val2);", bpp == 0 ? 8 : bpp == 1 ? 16 : 32);
203 		outln (		"    spix++;");
204 		outln (         "    }");
205 	} else if (hmode == HMODE_HALVE1) {
206 		outln (		"    spix += 2;");
207 	} else if (hmode == HMODE_HALVE2) {
208 		outln (		"    spix += 4;");
209 	} else {
210 		outln (		"    spix++;");
211 	}
212 }
213 
214 
put_dpix(const char * var)215 static void put_dpix (const char *var)
216 {
217 	outlnf ("    buf[dpix++] = %s;", var);
218 }
219 
out_sprite(DEPTH_T bpp,HMODE_T hmode,CMODE_T cmode,int aga,int cnt)220 static void out_sprite (DEPTH_T bpp, HMODE_T hmode, CMODE_T cmode, int aga, int cnt)
221 {
222 	if (aga) {
223 		if (cnt == 1) {
224 			outlnf ( "    if (spritepixels[dpix].data) {");
225 			outlnf ( "        sprcol = render_sprites (dpix + 0, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
226 			outlnf ( "        if (sprcol)");
227 			outlnf ( "            out_val = colors_for_drawing.acolors[sprcol];");
228 			outlnf ( "    }");
229 			put_dpix ("out_val");
230 		} else if (cnt == 2) {
231 			outlnf ( "    {");
232 			outlnf ( "    uae_u32 out_val1 = out_val;");
233 			outlnf ( "    uae_u32 out_val2 = out_val;");
234 			outlnf ( "    if (spritepixels[dpix + 0].data) {");
235 			outlnf ( "        sprcol = render_sprites (dpix + 0, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
236 			outlnf ( "        if (sprcol)");
237 			outlnf ( "            out_val1 = colors_for_drawing.acolors[sprcol];");
238 			outlnf ( "    }");
239 			outlnf ( "    if (spritepixels[dpix + 1].data) {");
240 			outlnf ( "        sprcol = render_sprites (dpix + 1, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
241 			outlnf ( "        if (sprcol)");
242 			outlnf ( "            out_val2 = colors_for_drawing.acolors[sprcol];");
243 			outlnf ( "    }");
244 			put_dpix ("out_val1");
245 			put_dpix ("out_val2");
246 			outlnf ( "    }");
247 		} else if (cnt == 4) {
248 			outlnf ( "    {");
249 			outlnf ( "    uae_u32 out_val1 = out_val;");
250 			outlnf ( "    uae_u32 out_val2 = out_val;");
251 			outlnf ( "    uae_u32 out_val3 = out_val;");
252 			outlnf ( "    uae_u32 out_val4 = out_val;");
253 			outlnf ( "    if (spritepixels[dpix + 0].data) {");
254 			outlnf ( "        sprcol = render_sprites (dpix + 0, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
255 			outlnf ( "        if (sprcol)");
256 			outlnf ( "            out_val1 = colors_for_drawing.acolors[sprcol];");
257 			outlnf ( "    }");
258 			outlnf ( "    if (spritepixels[dpix + 1].data) {");
259 			outlnf ( "        sprcol = render_sprites (dpix + 1, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
260 			outlnf ( "        if (sprcol)");
261 			outlnf ( "            out_val2 = colors_for_drawing.acolors[sprcol];");
262 			outlnf ( "    }");
263 			outlnf ( "    if (spritepixels[dpix + 2].data) {");
264 			outlnf ( "        sprcol = render_sprites (dpix + 2, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
265 			outlnf ( "        if (sprcol)");
266 			outlnf ( "            out_val3 = colors_for_drawing.acolors[sprcol];");
267 			outlnf ( "    }");
268 			outlnf ( "    if (spritepixels[dpix + 3].data) {");
269 			outlnf ( "        sprcol = render_sprites (dpix + 3, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
270 			outlnf ( "        if (sprcol)");
271 			outlnf ( "            out_val4 = colors_for_drawing.acolors[sprcol];");
272 			outlnf ( "    }");
273 			put_dpix ("out_val1");
274 			put_dpix ("out_val2");
275 			put_dpix ("out_val3");
276 			put_dpix ("out_val4");
277 			outlnf ( "    }");
278 		}
279 	} else {
280 		outlnf ( "    if (spritepixels[dpix].data) {");
281 		outlnf ( "        sprcol = render_sprites (dpix, %d, sprpix_val, %d);", cmode == CMODE_DUALPF ? 1 : 0, aga);
282 		outlnf ( "        if (sprcol) {");
283 		outlnf ( "            uae_u32 spcol = colors_for_drawing.acolors[sprcol];");
284 		outlnf ( "            out_val = spcol;");
285 		outlnf ( "        }");
286 		outlnf ( "    }");
287 		while (cnt-- > 0)
288 			put_dpix ("out_val");
289 	}
290 }
291 
292 
out_linetoscr_mode(DEPTH_T bpp,HMODE_T hmode,int aga,int spr,CMODE_T cmode)293 static void out_linetoscr_mode (DEPTH_T bpp, HMODE_T hmode, int aga, int spr, CMODE_T cmode)
294 {
295 	int old_indent = set_indent (8);
296 
297 	if (aga && cmode == CMODE_DUALPF) {
298 		outln (        "int *lookup    = bpldualpfpri ? dblpf_ind2_aga : dblpf_ind1_aga;");
299 		outln (        "int *lookup_no = bpldualpfpri ? dblpf_2nd2     : dblpf_2nd1;");
300 	} else if (cmode == CMODE_DUALPF)
301 		outln (        "int *lookup = bpldualpfpri ? dblpf_ind2 : dblpf_ind1;");
302 
303 
304 	/* TODO: add support for combining pixel writes in 8-bpp modes. */
305 
306 	if (bpp == DEPTH_16BPP && hmode != HMODE_DOUBLE && hmode != HMODE_DOUBLE2X && spr == 0) {
307 		outln (		"int rem;");
308 		outln (		"if (((long)&buf[dpix]) & 2) {");
309 		//if (CMODE_HAM != cmode)
310 			outln (	"    uae_u32 spix_val;");
311 		outln (		"    uae_u32 dpix_val = 0;");
312 
313 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
314 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
315 		out_linetoscr_do_incspix (bpp, hmode, aga, cmode, spr);
316 
317 		put_dpix ("dpix_val");
318 		outln (		"}");
319 		outln (		"if (dpix >= dpix_end)");
320 		outln (		"    return spix;");
321 		outln (		"rem = (((long)&buf[dpix_end]) & 2);");
322 		outln (		"if (rem)");
323 		outln (		"    dpix_end--;");
324 	}
325 
326 
327 	outln (		"while (dpix < dpix_end) {");
328 	if (spr)
329 		outln (		"    uae_u32 sprpix_val;");
330 	//if (CMODE_HAM != cmode)
331 		outln (		"    uae_u32 spix_val;");
332 	outln (			"    uae_u32 dpix_val = 0;");
333 	outln (			"    uae_u32 out_val  = 0;");
334 	outln (			"");
335 
336 	out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
337 	out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
338 	out_linetoscr_do_incspix (bpp, hmode, aga, cmode, spr);
339 
340 	outln (			"    out_val = dpix_val;");
341 
342 	if (hmode != HMODE_DOUBLE && hmode != HMODE_DOUBLE2X && bpp == DEPTH_16BPP && spr == 0) {
343 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
344 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
345 		out_linetoscr_do_incspix (bpp, hmode, aga, cmode, spr);
346 
347 		if (do_bigendian)
348 			outln (	"    out_val = (out_val << 16) | (dpix_val & 0xFFFF);");
349 		else
350 			outln (	"    out_val = (out_val & 0xFFFF) | (dpix_val << 16);");
351 	}
352 
353 	if (hmode == HMODE_DOUBLE) {
354 		if (bpp == DEPTH_8BPP) {
355 			outln (	"    *((uae_u16 *)&buf[dpix]) = (uae_u16) out_val;");
356 			outln (	"    dpix += 2;");
357 		} else if (bpp == DEPTH_16BPP) {
358 			if (spr) {
359 				out_sprite (bpp, hmode, cmode, aga, 2);
360 			} else {
361 				outln (	"    *((uae_u32 *)&buf[dpix]) = out_val;");
362 				outln (	"    dpix += 2;");
363 			}
364 		} else {
365 			if (spr) {
366 				out_sprite (bpp, hmode, cmode, aga, 2);
367 			} else {
368 				put_dpix ("out_val");
369 				put_dpix ("out_val");
370 			}
371 		}
372 	} else if (hmode == HMODE_DOUBLE2X) {
373 		if (bpp == DEPTH_8BPP) {
374 			outln (	"    *((uae_u32 *)&buf[dpix]) = (uae_u32) out_val;");
375 			outln (	"    dpix += 4;");
376 		} else if (bpp == DEPTH_16BPP) {
377 			if (spr) {
378 				out_sprite (bpp, hmode, cmode, aga, 4);
379 			} else {
380 				outln (	"    *((uae_u32 *)&buf[dpix]) = out_val;");
381 				outln (	"    dpix += 2;");
382 				outln (	"    *((uae_u32 *)&buf[dpix]) = out_val;");
383 				outln (	"    dpix += 2;");
384 			}
385 		} else {
386 			if (spr) {
387 				out_sprite (bpp, hmode, cmode, aga, 4);
388 			} else {
389 				put_dpix ("out_val");
390 				put_dpix ("out_val");
391 				put_dpix ("out_val");
392 				put_dpix ("out_val");
393 			}
394 		}
395 	} else {
396 		if (bpp == DEPTH_16BPP) {
397 			if (spr) {
398 				out_sprite (bpp, hmode, cmode, aga, 1);
399 			} else {
400 				outln (	"    *((uae_u32 *)&buf[dpix]) = out_val;");
401 				outln (	"    dpix += 2;");
402 			}
403 		} else {
404 			if (spr) {
405 				out_sprite (bpp, hmode, cmode, aga, 1);
406 			} else {
407 				put_dpix ("out_val");
408 			}
409 		}
410 	}
411 
412 	outln (		"}");
413 
414 
415 	if (bpp == DEPTH_16BPP && hmode != HMODE_DOUBLE && hmode != HMODE_DOUBLE2X && spr == 0) {
416 		outln (		"if (rem) {");
417 		//if (CMODE_HAM != cmode)
418 			outln (	"    uae_u32 spix_val;");
419 		outln (		"    uae_u32 dpix_val = 0;");
420 
421 		out_linetoscr_do_srcpix (bpp, hmode, aga, cmode, spr);
422 		out_linetoscr_do_dstpix (bpp, hmode, aga, cmode, spr);
423 		out_linetoscr_do_incspix (bpp, hmode, aga, cmode, spr);
424 
425 		put_dpix ("dpix_val");
426 		outln (		"}");
427 	}
428 
429 	set_indent (old_indent);
430 
431 	return;
432 }
433 
out_linetoscr(DEPTH_T bpp,HMODE_T hmode,int aga,int spr)434 static void out_linetoscr (DEPTH_T bpp, HMODE_T hmode, int aga, int spr)
435 {
436 	if (aga)
437 		outln  ("#ifdef AGA");
438 	else if ( (bpp > DEPTH_8BPP)
439 		&& ((HMODE_HALVE2 == hmode) || (HMODE_HALVE2F == hmode) )) {
440 		/* Some combinations are unused, and some combinations
441 		 * have special versions in drawing.c if ECS_DENISE is
442 		 * defined. */
443 		if (spr)
444 			return;
445 		else
446 			outln("#ifndef ECS_DENISE // Has special version in drawing.c");
447 	}
448 
449 	out_linetoscr_decl (bpp, hmode, aga, spr);
450 	outln  (	"{");
451 
452 	outlnf (	"    %s *buf = (%s *) xlinebuffer;", get_depth_type_str (bpp), get_depth_type_str (bpp));
453 	if (spr)
454 		outln ( "    uae_u8 sprcol;");
455 	if (aga)
456 		outln (	"    uae_u8 xor_val = bplxor;");
457 	outln  (	"");
458 
459 	outln  (	"    if (dp_for_drawing->ham_seen) {");
460 	out_linetoscr_mode (bpp, hmode, aga, spr, CMODE_HAM);
461 	outln  (	"    } else if (bpldualpf) {");
462 	out_linetoscr_mode (bpp, hmode, aga, spr, CMODE_DUALPF);
463 	outln  (	"    } else if (bplehb) {");
464 	out_linetoscr_mode (bpp, hmode, aga, spr, CMODE_EXTRAHB);
465 	outln  (	"    } else {");
466 	out_linetoscr_mode (bpp, hmode, aga, spr, CMODE_NORMAL);
467 
468 	outln  (	"    }\n");
469 	outln  (	"    return spix;");
470 	outln  (	"}");
471 
472 	if (aga)
473 		outln (	"#endif // AGA");
474 	else if ( (bpp > DEPTH_8BPP)
475 			&& ((HMODE_HALVE2 == hmode) || (HMODE_HALVE2F == hmode) ))
476 		outln ( "#endif //  ECS_DENISE");
477 
478 	outln  (	"");
479 }
480 
main(int argc,char * argv[])481 int main (int argc, char *argv[])
482 {
483 	DEPTH_T bpp;
484 	int aga, spr;
485 	HMODE_T hmode;
486 	int i = 1;
487 
488 	do_bigendian = 0;
489 
490 	for ( ; i < argc; i++) {
491 		if (argv[i][0] != '-')
492 			continue;
493 		if (argv[i][1] == 'b' && argv[i][2] == '\0')
494 			do_bigendian = 1;
495 	}
496 
497 	set_outfile (stdout);
498 
499 	outln ("/*");
500 	outln (" * P-UAE - The portable Amiga emulator.");
501 	outln (" *");
502 	outln (" * This file was generated by genlinetoscr. Don't edit.");
503 	outln (" */");
504 	outln ("");
505 
506 	for (bpp = DEPTH_16BPP; bpp <= DEPTH_MAX; bpp++) {
507 		for (aga = 0; aga <= 1 ; aga++) {
508 			if (aga && bpp == DEPTH_8BPP)
509 				continue;
510 			for (spr = 0; spr <= 1; spr++) {
511 				for (hmode = HMODE_NORMAL; hmode <= HMODE_MAX; hmode++)
512 					out_linetoscr (bpp, hmode, aga, spr);
513 			}
514 		}
515 	}
516 	return 0;
517 }
518