1 
2 
3 /*----------------------------------------------------------*/
4 /*															*/
5 /*						LIBMESH V 3.0						*/
6 /*															*/
7 /*----------------------------------------------------------*/
8 /*															*/
9 /*	Description:		handle .meshb file format I/O		*/
10 /*	Author:				Loic MARECHAL						*/
11 /*	Creation date:		aug  2 2003							*/
12 /*	Last modification:	jan 25 2006							*/
13 /*															*/
14 /*----------------------------------------------------------*/
15 
16 
17 /*----------------------------------------------------------*/
18 /* Includes													*/
19 /*----------------------------------------------------------*/
20 
21 #include <string.h>
22 #include <float.h>
23 #include <math.h>
24 #include <ctype.h>
25 #include "libmesh3.h"
26 
27 
28 /*----------------------------------------------------------*/
29 /* Global variables											*/
30 /*----------------------------------------------------------*/
31 
32 char *LM_kw_table[ LM_NBKW + 1 ][3] =
33 {	{"Reserved", "", ""},
34 	{"MeshVersionFormatted", "", "i"},
35 	{"Reserved", "", ""},
36 	{"Dimension", "", "i"},
37 	{"Vertices", "i", "dri"},
38 	{"Edges", "i", "iii"},
39 	{"Triangles", "i", "iiii"},
40 	{"Quadrilaterals", "i", "iiiii"},
41 	{"Tetrahedra", "i", "iiiii"},
42 	{"Pentahedra", "i", "iiiiiii"},
43 	{"Hexahedra", "i", "iiiiiiiii"},
44 	{"SubDomainFromGeom", "i", "iiii"},
45 	{"SubDomainFromMesh", "i", "iiii"},
46 	{"Corners", "i", "i"},
47 	{"Ridges", "i", "i"},
48 	{"RequiredVertices", "i", "i"},
49 	{"RequiredEdges", "i", "i"},
50 	{"RequiredTriangles", "i", "i"},
51 	{"RequiredQuadrilaterals", "i", "i"},
52 	{"TangentAtEdgeVertices", "i", "iii"},
53 	{"NormalAtVertices", "i", "ii"},
54 	{"NormalAtTriangleVertices", "i", "iii"},
55 	{"NormalAtQuadrilateralVertices", "i", "iiii"},
56 	{"AngleOfCornerBound", "", "r"},
57 	{"Geometry", "", "c"},
58 	{"VertexOnGeometricVertex", "i", "ii"},
59 	{"VertexOnGeometricEdge", "i", "iir"},
60 	{"VertexOnGeometricTriangle", "i", "iirr"},
61 	{"VertexOnGeometricQuadrilateral", "i", "iirr"},
62 	{"EdgeOnGeometricEdge", "i", "ii"},
63 	{"TriangleOnGeometricTriangle", "i", "ii"},
64 	{"TriangleOnGeometricQuadrilateral", "i", "ii"},
65 	{"QuadrilateralOnGeometricTriangle", "i", "ii"},
66 	{"QuadrilateralOnGeometricQuadrilateral", "i", "ii"},
67 	{"MeshSupportOfVertices", "", "c"},
68 	{"VertexOnSupportVertex", "i", "ii"},
69 	{"VertexOnSupportEdge", "i", "iir"},
70 	{"VertexOnSupportTriangle", "i", "iirr"},
71 	{"VertexOnSupportQuadrilateral", "i", "iirr"},
72 	{"VertexOnSupportTetrahedron", "i", "iirrr"},
73 	{"VertexOnSupportPentahedron", "i", "iirrr"},
74 	{"VertexOnSupportHexahedron", "i", "iirrr"},
75 	{"CrackedEdges", "i", "ii"},
76 	{"CrackedTriangles", "i", "ii"},
77 	{"CrackedQuadrilaterals", "i", "ii"},
78 	{"EquivalentEdges", "i", "ii"},
79 	{"EquivalentTriangles", "i", "ii"},
80 	{"EquivalentQuadrilaterals", "i", "ii"},
81 	{"PhysicsReference", "i", "ic"},
82 	{"IncludeFile", "", "c"},
83 	{"BoundingBox", "", "drdr"},
84 	{"Identifier", "", "c"},
85 	{"IdentityOfGeometry", "", "c"},
86 	{"IdentityOfMeshSupport", "", "c"},
87 	{"End", "", ""},
88 	{"Reserved", "", ""},
89 	{"Reserved", "", ""},
90 	{"Reserved", "", ""},
91 	{"Reserved", "", ""},
92 	{"Tangents", "i", "dr"},
93 	{"Normals", "i", "dr"},
94 	{"TangentAtVertices", "i", "ii"},
95 	{"SolAtVertices", "i", "sr"},
96 	{"SolAtEdges", "i", "sr"},
97 	{"SolAtTriangles", "i", "sr"},
98 	{"SolAtQuadrilaterals", "i", "sr"},
99 	{"SolAtTetrahedra", "i", "sr"},
100 	{"SolAtPentahedra", "i", "sr"},
101 	{"SolAtHexahedra", "i", "sr"},
102 	{"DSolAtVertices", "i", "sr"},
103 	{"ISolAtVertices", "i", "i"},
104 	{"ISolAtEdges", "i", "ii"},
105 	{"ISolAtTriangles", "i", "iii"},
106 	{"ISolAtQuadrilaterals", "i", "iiii"},
107 	{"ISolAtTetrahedra", "i", "iiii"},
108 	{"ISolAtPentahedra", "i", "iiiiii"},
109 	{"ISolAtHexahedra", "i", "iiiiiiii"},
110 	{"Iterations","","i"},
111 	{"Time","","r"},
112 	{"VertexHack","","drdr"}
113  };
114 
115 
116 /*----------------------------------------------------------*/
117 /* Prototypes of local procedures							*/
118 /*----------------------------------------------------------*/
119 
120 static void write_kw(LM_mesh_struct *, int);
121 static int read_int(LM_mesh_struct *);
122 static void write_int(LM_mesh_struct *, int);
123 static void file2kw_tab(LM_mesh_struct *);
124 static void kw_tab2file(LM_mesh_struct *);
125 static int expand_format(LM_mesh_struct *, int, char *);
126 static void swap_bytes(void *, void *, int);
127 static void read_sol_headers(LM_mesh_struct *);
128 
129 
130 /*----------------------------------------------------------*/
131 /* Open a mesh file in read or write mode					*/
132 /*----------------------------------------------------------*/
133 
LM_open_mesh(char * filename,int mode,LM_mesh_struct * mesh,...)134 int LM_open_mesh(char *filename, int mode, LM_mesh_struct *mesh, ...)
135 {
136 	int i;
137 	va_list pa;
138 
139 
140 	/*---------------------*/
141 	/* MESH STRUCTURE INIT */
142 	/*---------------------*/
143 
144 	/* Init the kw table */
145 
146 	for(i=0;i<=LM_NBKW;i++)
147 	{
148 		mesh->kw_counters[i] = 0;
149 		mesh->kw_pos[i][0] = 0;
150 		mesh->kw_pos[i][1] = 0;
151 		mesh->kw_pos[i][2] = 0;
152 		mesh->sol_headers[i] = NULL;
153 	}
154 
155 	/* Allocate a string large enough to contain the full filename and path plus the ".meshb" extension. */
156 
157 	mesh->filename = (char *)calloc((strlen(filename) + 7), sizeof(char));
158 	strcpy(mesh->filename, filename);
159 
160 	/* Store the opening mode (read or write) and guess the filetype (binary or ascii) depending on the extension */
161 
162 	mesh->mode = mode;
163 	mesh->current_kw = mesh->type = 0;
164 	mesh->endian = 1;
165 
166 	if(strstr(mesh->filename, ".meshb"))
167 		mesh->type |= (LM_BINARY | LM_MESH);
168 	else if(strstr(mesh->filename, ".mesh"))
169 		mesh->type |= (LM_ASCII | LM_MESH);
170 	else if(strstr(mesh->filename, ".solb"))
171 		mesh->type |= (LM_BINARY | LM_SOL);
172 	else if(strstr(mesh->filename, ".sol"))
173 		mesh->type |= (LM_ASCII | LM_SOL);
174 	else
175 		return(0);
176 
177 	/* Open the file in the required mode and initialyse the mesh structure */
178 
179 	if(mesh->mode == LM_READ)
180 	{
181 
182 		/*-----------------------*/
183 		/* OPEN FILE FOR READING */
184 		/*-----------------------*/
185 
186 		/* Create the name string and open the file */
187 
188 		if(!(mesh->handle = fopen(mesh->filename, "rb")))
189 			return(0);
190 
191 		/* Read the endian tag and the mesh version in binary */
192 
193 		if(mesh->type & LM_BINARY)
194 		{
195 			mesh->endian = read_int(mesh);
196 
197 			if( (mesh->endian != 1) && (mesh->endian != 16777216) )
198 				return(0);
199 
200 			mesh->version = read_int(mesh);
201 		}
202 
203 
204 		/*------------*/
205 		/* KW READING */
206 		/*------------*/
207 
208 		/* Read the list of kw present in the file */
209 
210 		file2kw_tab(mesh);
211 
212 		/* Check the mesh dimension */
213 
214 		if(!mesh->kw_counters[ LM_Dimension ])
215 			return(0);
216 
217 		LM_read_field(mesh, LM_Dimension, 1, &mesh->dimension);
218 
219 		if( (mesh->dimension != 2) && (mesh->dimension != 3) )
220 			return(0);
221 
222 		/* Read the meshversion in ascii case */
223 
224 		if(mesh->type & LM_ASCII)
225 			LM_read_field(mesh, LM_MeshVersionFormatted, 1, &mesh->version);
226 
227 		/* And read the extended sol headers */
228 
229 		read_sol_headers(mesh);
230 	}
231 	else if(mesh->mode == LM_WRITE)
232 	{
233 
234 		/*-----------------------*/
235 		/* OPEN FILE FOR WRITING */
236 		/*-----------------------*/
237 
238 		/* Check if the user provided a valid dimension */
239 
240 		va_start(pa, mesh);
241 		mesh->dimension = va_arg(pa, int);
242 		va_end(pa);
243 
244 		if( (mesh->dimension != 2) && (mesh->dimension != 3) )
245 			return(0);
246 
247 		/* If no extension has been provided, create a binary file */
248 
249 		if(!(mesh->handle = fopen(mesh->filename, "wb")))
250 			return(0);
251 
252 
253 		/*------------*/
254 		/* KW WRITING */
255 		/*------------*/
256 
257 		/* Initialyse the required fields. The kw will be stored afterward. */
258 
259 		mesh->version = LM_MESH_VERSION;
260 		mesh->endian = 1;
261 
262 		/* Write the mesh version */
263 
264 		if(mesh->type & LM_ASCII)
265 			LM_write_field(mesh, LM_MeshVersionFormatted, 1, &mesh->version);
266 		else
267 		{
268 			write_int(mesh, mesh->endian);
269 			write_int(mesh, mesh->version);
270 		}
271 
272 		/* Write the mesh dimension */
273 
274 		LM_write_field(mesh, LM_Dimension, 1, &mesh->dimension);
275 	}
276 	else
277 		return(0);
278 
279 	return(1);
280 }
281 
282 
283 /*----------------------------------------------------------*/
284 /* Close a meshfile in the right way						*/
285 /*----------------------------------------------------------*/
286 
LM_close_mesh(LM_mesh_struct * mesh)287 int LM_close_mesh(LM_mesh_struct *mesh)
288 {
289 	if(mesh->mode == LM_WRITE)
290 	{
291 		/* Test if the user wrote the "End" kw */
292 
293 		if(!mesh->kw_counters[ LM_End ])
294 			LM_write_field(mesh, LM_End, 0, NULL);
295 
296 		/* Write down the number lines written in each field to the file */
297 
298 		kw_tab2file(mesh);
299 	}
300 
301 	if(fclose(mesh->handle))
302 		return(0);
303 	else
304 		return(1);
305 }
306 
307 
308 /*----------------------------------------------------------*/
309 /* Bufferized read of a whole orpart of a field				*/
310 /*----------------------------------------------------------*/
311 
LM_read_field(LM_mesh_struct * mesh,int kw_code,int nbl,void * buffer)312 int LM_read_field(LM_mesh_struct *mesh, int kw_code, int nbl, void *buffer)
313 {
314 	int i, j, swaped, size, *int_buffer = (int *)buffer, string_size;
315 	float *flt_buffer = (float *)buffer;
316 	char format[256], letter, str_buf[256];
317 
318 	/* Check if the kw code is valid */
319 
320 	if( (kw_code < 1) || (kw_code > LM_NBKW) )
321 		return(0);
322 
323 	/* Check if this kw has a format */
324 
325 	if(!strlen(LM_kw_table[ kw_code ][2]))
326 		return(0);
327 
328 	/* If this kw is only a header, the number of lines to be read is set to one */
329 
330 	if(!strlen(LM_kw_table[ kw_code ][1]))
331 		nbl = 1;
332 
333 	/* Check if the user is not asking more lines than the remaining lines in the file */
334 
335 	if(nbl > mesh->kw_counters[ kw_code ] - mesh->kw_pos[ kw_code ][2])
336 		nbl = mesh->kw_counters[ kw_code ] - mesh->kw_pos[ kw_code ][2];
337 
338 	if(!nbl)
339 		return(0);
340 
341 	/* Set the curent position in file to the begining of this kw's data */
342 
343 	fseek(mesh->handle, mesh->kw_pos[ kw_code ][1], SEEK_SET);
344 
345 	/* Transform the internal format into a "c" format string for the scanf and compute the size of
346 		field's line in order to compute the right adresses in the buffer */
347 
348 	size = expand_format(mesh, kw_code, format);
349 
350 	if(mesh->type & LM_ASCII)
351 	{
352 		for(i=0;i<nbl;i++)
353 			for(j=0;j<size;j++)
354 				if(format[j] == 'i')
355 					fscanf(mesh->handle, "%d", &int_buffer[ i * size + j ]);
356 				else if(format[j] == 'r')
357 					fscanf(mesh->handle, "%g", &flt_buffer[ i * size + j ]);
358 				else if(format[j] == 'c')
359 				{
360 					string_size = 0;
361 
362 					do
363 					{
364 						fscanf(mesh->handle, "%c", &letter);
365 					}while(letter != '"');
366 
367 					do
368 					{
369 						fscanf(mesh->handle, "%c", &letter);
370 						str_buf[ string_size++ ] = letter;
371 					}while( (letter != '"') && (string_size <= 256) );
372 
373 					str_buf[ string_size-1 ] = 0;
374 
375 					memset(&flt_buffer[ i * size + j ], 0, 256);
376 					strcpy((char *)&flt_buffer[ i * size + j ], str_buf);
377 				}
378 	}
379 	else
380 	{
381 		fread(buffer, nbl * size * 4, 1, mesh->handle);
382 
383 		/* Swap the bytes in the whole buffer in case of different endian */
384 
385 		if(mesh->endian != 1)
386 			for(i=0;i<nbl*size;i++)
387 			{
388 				swap_bytes((void *)&int_buffer[i], (void *)&swaped, 4);
389 				int_buffer[i] = swaped;
390 			}
391 	}
392 
393 	/* Then store the curent position and the total number of read lines in case we didn't read the whole data */
394 
395 	mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
396 	mesh->kw_pos[ kw_code ][2] += nbl;
397 
398 	return(nbl);
399 }
400 
401 
402 /*----------------------------------------------------------*/
403 /* Bufferized write of a whole field or part of it			*/
404 /*----------------------------------------------------------*/
405 
LM_write_field(LM_mesh_struct * mesh,int kw_code,int nbl,void * buffer,...)406 int LM_write_field(LM_mesh_struct *mesh, int kw_code, int nbl, void *buffer, ...)
407 {
408 	int i, j, size, *int_buffer = (int *)buffer, nbsol;
409 	float *flt_buffer = (float *)buffer;
410 	char format[256];
411 	va_list pa;
412 
413 	/* Check if the kw code is valid */
414 
415 	if( (kw_code < 1) || (kw_code > LM_NBKW) )
416 		return(0);
417 
418 	/* Read further arguments if this kw is solution field and the extra header was not provided by the user */
419 
420 	if(!mesh->sol_headers[ kw_code ] && !strcmp(LM_kw_table[ kw_code ][2], "sr"))
421 	{
422 		va_start(pa, buffer);
423 
424 		nbsol = va_arg(pa, int);
425 
426 		if(!(mesh->sol_headers[ kw_code ] = malloc((nbsol+2) * sizeof(int))))
427 			return(0);
428 
429 		mesh->sol_headers[ kw_code ][0] = nbsol;
430 		mesh->sol_headers[ kw_code ][1] = 0;
431 
432 		for(i=1;i<=nbsol;i++)
433 		{
434 			mesh->sol_headers[ kw_code ][i+1] = va_arg(pa, int);
435 
436 			switch(mesh->sol_headers[ kw_code ][i+1])
437 			{
438 				case 1 : mesh->sol_headers[ kw_code ][1] += 1; break;
439 				case 2 : mesh->sol_headers[ kw_code ][1] += mesh->dimension; break;
440 				case 3 : mesh->sol_headers[ kw_code ][1] += (mesh->dimension * (mesh->dimension+1)) / 2; break;
441 				case 4 : mesh->sol_headers[ kw_code ][1] += mesh->dimension * mesh->dimension; break;
442 			}
443 		}
444 
445 		va_end(pa);
446 	}
447 
448 	/* If this kw is only a header, the number of lines to be read is set to one */
449 
450 	if(!strlen(LM_kw_table[ kw_code ][1]))
451 		nbl = 1;
452 
453 	if(!mesh->kw_counters[ kw_code ])
454 		write_kw(mesh, kw_code);
455 
456 	mesh->kw_counters[ kw_code ] += nbl;
457 
458 	/* Check if this kw has a format */
459 
460 	if(!strlen(LM_kw_table[ kw_code ][2]))
461 		return(0);
462 
463 	size = expand_format(mesh, kw_code, format);
464 
465 	if(mesh->type & LM_ASCII)
466 	{
467 		for(i=0;i<nbl;i++)
468 		{
469 			for(j=0;j<size;j++)
470 				if(format[j] == 'i')
471 					fprintf(mesh->handle, "%d ", int_buffer[ i * size + j ]);
472 				else if(format[j] == 'r')
473 					fprintf(mesh->handle, "%g ", flt_buffer[ i * size + j ]);
474 				else if(format[j] == 'c')
475 				{
476 					fputc('"', mesh->handle);
477 					fprintf(mesh->handle, "%s", (char *)&flt_buffer[ i * size + j ]);
478 					fputc('"', mesh->handle);
479 				}
480 
481 			fprintf(mesh->handle, "\n");
482 		}
483 	}
484 	else
485 		fwrite(buffer, nbl * size * 4, 1, mesh->handle);
486 
487 	mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
488 
489 	return(1);
490 }
491 
492 
493 /*----------------------------------------------------------*/
494 /* Single line read											*/
495 /*----------------------------------------------------------*/
496 
LM_read_line(LM_mesh_struct * mesh,int kw_code,...)497 int LM_read_line(LM_mesh_struct *mesh, int kw_code, ...)
498 {
499 	float buffer[10], *ptr_flt;
500 	int i, size;
501 	char format[256];
502 	va_list pa;
503 
504 	/* Check wether this kw is not a simple header */
505 
506 	if(!strlen(LM_kw_table[ kw_code ][2]))
507 		return(0);
508 
509 	/* Get a one line buffer */
510 
511 	LM_read_field(mesh, kw_code, 1, buffer);
512 
513 	/* Start decoding the arguments */
514 
515 	va_start(pa, kw_code);
516 	size = expand_format(mesh, kw_code, format);
517 
518 	for(i=0;i<size;i++)
519 	{
520 		ptr_flt = va_arg(pa, float *);
521 		*ptr_flt = buffer[i];
522 	}
523 
524 	va_end(pa);
525 
526 	/* return the number of arguments filled */
527 
528 	return(size);
529 }
530 
531 
532 /*----------------------------------------------------------*/
533 /* Single line write										*/
534 /*----------------------------------------------------------*/
535 
LM_write_line(LM_mesh_struct * mesh,int kw_code,...)536 int LM_write_line(LM_mesh_struct *mesh, int kw_code, ...)
537 {
538 	float buffer[10], *ptr_flt;
539 	int i, size;
540 	char format[256];
541 	va_list pa;
542 
543 	/* Check wether this kw is not a simple header */
544 
545 	if(!strlen(LM_kw_table[ kw_code ][2]))
546 		return(0);
547 
548 	/* Start decoding the arguments */
549 
550 	va_start(pa, kw_code);
551 	size = expand_format(mesh, kw_code, format);
552 
553 	for(i=0;i<size;i++)
554 	{
555 		ptr_flt = va_arg(pa, float *);
556 		buffer[i] = *ptr_flt;
557 	}
558 
559 	va_end(pa);
560 
561 	/* Write a one line buffer */
562 
563 	LM_write_field(mesh, kw_code, 1, buffer);
564 
565 	/* return the number of arguments filled */
566 
567 	return(size);
568 }
569 
570 
571 /*----------------------------------------------------------*/
572 /* Find every kw present in a meshfile						*/
573 /*----------------------------------------------------------*/
574 
file2kw_tab(LM_mesh_struct * mesh)575 static void file2kw_tab(LM_mesh_struct *mesh)
576 {
577 	int kw_code, next_pos;
578 	char str[256];
579 
580 	if(mesh->type & LM_ASCII)
581 	{
582 		/* Scan each string of the file until the end */
583 
584 		while(fscanf(mesh->handle, "%s", str) != EOF)
585 		{
586 			/* Fast test in order to reject quickly the numeric values */
587 
588 			if(isalpha(str[0]))
589 			{
590 				/* Search which kw code this string is associated with */
591 
592 				for(kw_code=1; kw_code<= LM_NBKW; kw_code++)
593 					if(!strcmp(str, LM_kw_table[ kw_code ][0]))
594 					{
595 						/* The base position (0) in the file is set right after the kw */
596 
597 						mesh->kw_pos[ kw_code ][0] = ftell(mesh->handle);
598 
599 						/* If this kw has a header, read the number of lines */
600 
601 						if(!strcmp(LM_kw_table[ kw_code ][1], "i"))
602 							mesh->kw_counters[ kw_code ] = read_int(mesh);
603 						else
604 							mesh->kw_counters[ kw_code ] = 1;
605 
606 						/* The curent position (1) in the file is set right before the data */
607 
608 						mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
609 						break;
610 					}
611 			}
612 			else if(str[0] == '#')
613 				while(fgetc(mesh->handle) != '\n');
614 		}
615 	}
616 	else
617 	{
618 		/* Jump through kw positions in the file */
619 
620 		do
621 		{
622 			kw_code = read_int(mesh);
623 
624 			/* Check if this kw belongs to this mesh version */
625 
626 			if( (kw_code >= 1) && (kw_code <= LM_NBKW) )
627 			{
628 				/* The base position (0) in the file is set right after the kw */
629 
630 				mesh->kw_pos[ kw_code ][0] =  ftell(mesh->handle);
631 
632 				/* Read the next kw position */
633 
634 				next_pos =  read_int(mesh);
635 
636 				/* If this kw has a header, read the number of lines */
637 
638 				if(!strcmp(LM_kw_table[ kw_code ][1], "i"))
639 					mesh->kw_counters[ kw_code ] = read_int(mesh);
640 				else
641 					mesh->kw_counters[ kw_code ] = 1;
642 
643 				/* The curent position (1) in the file is set right before the data */
644 
645 				mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
646 			}
647 			else
648 			{
649 				/* Otherwise, read the next kw position in order to skip these unknown kw */
650 
651 				next_pos =  read_int(mesh);
652 			}
653 
654 			/* Go to the next kw */
655 
656 			if(next_pos)
657 				fseek(mesh->handle, next_pos, SEEK_SET);
658 		}while(next_pos);
659 	}
660 }
661 
662 
663 /*----------------------------------------------------------*/
664 /* Update the number of lines written for each kw			*/
665 /*----------------------------------------------------------*/
666 
kw_tab2file(LM_mesh_struct * mesh)667 static void kw_tab2file(LM_mesh_struct *mesh)
668 {
669 	int i;
670 
671 	for(i=1;i<=LM_NBKW;i++)
672 		if( mesh->kw_counters[i] && strlen(LM_kw_table[i][2]) )
673 			write_kw(mesh, i);
674 }
675 
676 
677 /*----------------------------------------------------------*/
678 /* Write the string associated with the kw code				*/
679 /*----------------------------------------------------------*/
680 
write_kw(LM_mesh_struct * mesh,int kw_code)681 static void write_kw(LM_mesh_struct *mesh, int kw_code)
682 {
683 	int i;
684 
685 	if(mesh->type & LM_ASCII)
686 	{
687 		/* Test if it is the first time this kw is written */
688 
689 		if(!mesh->kw_counters[ kw_code ])
690 		{
691 			/* If so, write the string and reserve some place afterward in order to store the
692 				number of lines */
693 
694 			fprintf(mesh->handle, "\n%s\n", LM_kw_table[ kw_code ][0]);
695 
696 			mesh->kw_pos[ kw_code ][0] = ftell(mesh->handle);
697 
698 			if(!strcmp("i", LM_kw_table[ kw_code ][1]))
699 				fprintf(mesh->handle, "          \n");
700 
701 			/* In case of solution field, write the extended header at once */
702 
703 			if(mesh->sol_headers[ kw_code ])
704 			{
705 				fprintf(mesh->handle, "%d ", mesh->sol_headers[ kw_code ][0]);
706 
707 				for(i=1;i<=mesh->sol_headers[ kw_code ][0];i++)
708 					fprintf(mesh->handle, "%d ", mesh->sol_headers[ kw_code ][i+1]);
709 
710 				fprintf(mesh->handle, "\n\n");
711 			}
712 
713 			/* Store the positions right after the kw in order to write the number of lines at closing time.
714 				Store the position right before the data for the write_field process. */
715 
716 			mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
717 		}
718 		else
719 		{
720 			/* If this kw has already be written in the file and has a header, go to pos(0) and write
721 				down the final value */
722 
723 			if(strcmp("i", LM_kw_table[ kw_code ][1]))
724 				return;
725 
726 			fseek(mesh->handle, mesh->kw_pos[ kw_code][0], SEEK_SET);
727 			fprintf(mesh->handle, "%d\n", mesh->kw_counters[ kw_code ]);
728 		}
729 	}
730 	else
731 	{
732 		/* Test if it is the first time this kw is written */
733 
734 		if(!mesh->kw_counters[ kw_code ])
735 		{
736 			/* If so, write the code, store the position afterward, reserve an int for the next kw position
737 				and write the number of lines */
738 
739 			write_int(mesh, kw_code);
740 			mesh->kw_pos[ kw_code ][0] = ftell(mesh->handle);
741 			write_int(mesh, 0);
742 
743 			/* Set the next kw pos in the previously written kw */
744 
745 			if(mesh->current_kw)
746 			{
747 				fseek(mesh->handle, mesh->kw_pos[ mesh->current_kw ][0], SEEK_SET);
748 				write_int(mesh, mesh->kw_pos[ kw_code ][0] - 4);
749 				fseek(mesh->handle, mesh->kw_pos[ kw_code ][0] + 4, SEEK_SET);
750 			}
751 
752 			mesh->current_kw = kw_code;
753 
754 			if(!strcmp("i", LM_kw_table[ kw_code ][1]))
755 				write_int(mesh, 0);
756 
757 			/* In case of solution field, write the extended header at once */
758 
759 			if(mesh->sol_headers[ kw_code ])
760 			{
761 				write_int(mesh, mesh->sol_headers[ kw_code ][0]);
762 
763 				for(i=1;i<=mesh->sol_headers[ kw_code ][0];i++)
764 					write_int(mesh, mesh->sol_headers[ kw_code ][i+1]);
765 			}
766 
767 			mesh->kw_pos[ kw_code ][1] = ftell(mesh->handle);
768 		}
769 		else
770 		{
771 			/* Write the number of lines written at closing time */
772 
773 			if(strcmp("i", LM_kw_table[ kw_code ][1]))
774 				return;
775 
776 			fseek(mesh->handle, mesh->kw_pos[ kw_code ][0] + 4, SEEK_SET);
777 			write_int(mesh, mesh->kw_counters[ kw_code ]);
778 		}
779 	}
780 }
781 
782 
783 /*----------------------------------------------------------*/
784 /* Read an integer in a mesh file							*/
785 /*----------------------------------------------------------*/
786 
read_int(LM_mesh_struct * mesh)787 static int read_int(LM_mesh_struct *mesh)
788 {
789 	int swaped, integer = 0;
790 
791 	if(mesh->type & LM_ASCII)
792 		fscanf(mesh->handle, "%d", &integer);
793 	else
794 	{
795 		/* Read a 4 bytes block in the file */
796 
797 		fread(&integer, 4, 1, mesh->handle);
798 
799 		if(mesh->endian != 1)
800 		{
801 			swap_bytes((void *)&integer, (void *)&swaped, 4);
802 			integer = swaped;
803 		}
804 	}
805 
806 	return(integer);
807 }
808 
809 
810 /*----------------------------------------------------------*/
811 /* Write an integer in a mesh file							*/
812 /*----------------------------------------------------------*/
813 
write_int(LM_mesh_struct * mesh,int integer)814 static void write_int(LM_mesh_struct *mesh, int integer)
815 {
816 	if(mesh->type & LM_ASCII)
817 		fprintf(mesh->handle, "%d ", integer);
818 	else
819 		fwrite(&integer, 4, 1, mesh->handle);
820 }
821 
822 
823 /*----------------------------------------------------------*/
824 /* Convert little endian <-> big endian						*/
825 /*----------------------------------------------------------*/
826 
swap_bytes(void * c1,void * c2,int nbytes)827 static void swap_bytes(void *c1, void *c2, int nbytes)
828 {
829   int   k;
830   char *c11, *c22;
831 
832   c11 = (char*)c1;
833   c22 = (char*)c2;
834 
835   for (k=0; k<nbytes; k++)
836     c22[k] = c11[ nbytes-k-1 ];
837 }
838 
839 
840 /*----------------------------------------------------------*/
841 /* Expand the compacted format and compute the line size	*/
842 /*----------------------------------------------------------*/
843 
expand_format(LM_mesh_struct * mesh,int kw_code,char * out_format)844 static int expand_format(LM_mesh_struct *mesh, int kw_code, char *out_format)
845 {
846 	int i, j, duplicate_next = 0, size = 0;
847 	char *in_format = LM_kw_table[ kw_code ][2];
848 
849 	out_format[0] = '\0';
850 
851 	/* Scan each character of the format string */
852 
853 	for(i=0;i<strlen(in_format);i++)
854 	{
855 		if( (in_format[i] == 'i') || (in_format[i] == 'r') )
856 		{
857 			if(!duplicate_next)
858 				duplicate_next = 1;
859 
860 			for(j=1;j<=duplicate_next;j++)
861 			{
862 				strncat(out_format, &in_format[i], 1);
863 				size++;
864 			}
865 
866 			duplicate_next = 0;
867 		}
868 		else if(in_format[i] == 'c')
869 		{
870 			strncat(out_format, &in_format[i], 1);
871 			size += 64;
872 		}
873 		else if(in_format[i] == 'd')
874 		{
875 			/* 'd' means duplicate the next character mesh->dimension times */
876 
877 			duplicate_next = mesh->dimension;
878 		}
879 		else if(in_format[i] == 's')
880 		{
881 			/* 's' means duplicate the next character mesh->solsize times */
882 
883 			duplicate_next = mesh->sol_headers[ kw_code ][1];
884 		}
885 	}
886 
887 	/* Return the sum of item to be read */
888 
889 	return(size);
890 }
891 
892 
893 /*----------------------------------------------------------*/
894 /* Read the extended sol headers							*/
895 /*----------------------------------------------------------*/
896 
read_sol_headers(LM_mesh_struct * mesh)897 static void read_sol_headers(LM_mesh_struct *mesh)
898 {
899 	int i, j, nbsol, solsize;
900 
901 	for(i=1;i<=LM_NBKW;i++)
902 	{
903 		/* If the kw is a special Sol field, read the extended header */
904 
905 		if(!mesh->kw_counters[i] || strcmp(LM_kw_table[i][2], "sr"))
906 			continue;
907 
908 		/* Set the curent position in file to the begining of this kw's data */
909 
910 		fseek(mesh->handle, mesh->kw_pos[i][1], SEEK_SET);
911 
912 		nbsol = read_int(mesh);
913 
914 		if(mesh->sol_headers[i] = malloc((nbsol+2) * sizeof(int)))
915 		{
916 			mesh->sol_headers[i][0] = nbsol;
917 			solsize = 0;
918 
919 			for(j=1;j<=nbsol;j++)
920 			{
921 				mesh->sol_headers[i][j+1] = read_int(mesh);
922 
923 				switch(mesh->sol_headers[i][j+1])
924 				{
925 					case LM_SCALAR     : solsize += 1; break;
926 					case LM_VECTOR     : solsize += mesh->dimension; break;
927 					case LM_SYM_MATRIX : solsize += (mesh->dimension * (mesh->dimension+1)) / 2; break;
928 					case LM_MATRIX     : solsize += mesh->dimension * mesh->dimension; break;
929 				}
930 
931 				mesh->sol_headers[i][1] = solsize;
932 			}
933 
934 			mesh->kw_pos[i][1] = ftell(mesh->handle);
935 		}
936 	}
937 }
938