1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include "gts-private.h"
27 const guint gts_major_version
= GTS_MAJOR_VERSION
;
28 const guint gts_minor_version
= GTS_MINOR_VERSION
;
29 const guint gts_micro_version
= GTS_MICRO_VERSION
;
30 const guint gts_interface_age
= 1;
31 const guint gts_binary_age
= 1;
33 static gboolean
char_in_string (char c
, const char * s
)
41 static GtsFile
* file_new (void)
45 f
= g_malloc (sizeof (GtsFile
));
50 f
->token
= g_string_new ("");
55 f
->scope
= f
->scope_max
= 0;
56 f
->delimiters
= g_strdup (" \t");
57 f
->comments
= g_strdup (GTS_COMMENTS
);
58 f
->tokens
= g_strdup ("\n{}()=");
65 * @fp: a file pointer.
67 * Returns: a new #GtsFile.
69 GtsFile
* gts_file_new (FILE * fp
)
73 g_return_val_if_fail (fp
!= NULL
, NULL
);
77 gts_file_next_token (f
);
83 * gts_file_new_from_string:
86 * Returns: a new #GtsFile.
88 GtsFile
* gts_file_new_from_string (const gchar
* s
)
92 g_return_val_if_fail (s
!= NULL
, NULL
);
95 f
->s1
= f
->s
= g_strdup (s
);
96 gts_file_next_token (f
);
105 * Frees all the memory allocated for @f.
107 void gts_file_destroy (GtsFile
* f
)
109 g_return_if_fail (f
!= NULL
);
111 g_free (f
->delimiters
);
112 g_free (f
->comments
);
118 g_string_free (f
->token
, TRUE
);
125 * @format: the standard sprintf() format string.
126 * @args: the list of parameters to insert into the format string.
128 * Sets the @error field of @f using g_strdup_vprintf().
130 * This function can be called only once and disables any other
131 * operation on @f (gts_file_close() excepted).
133 void gts_file_verror (GtsFile
* f
,
134 const gchar
* format
,
137 g_return_if_fail (f
!= NULL
);
138 g_return_if_fail (format
!= NULL
);
140 g_assert (f
->type
!= GTS_ERROR
);
141 f
->error
= g_strdup_vprintf (format
, args
);
148 * @format: the standard sprintf() format string.
149 * @...: the parameters to insert into the format string.
151 * Sets the @error field of @f using gts_file_verror().
153 * This function can be called only once and disables any other
154 * operation on @f (gts_file_close() excepted).
156 void gts_file_error (GtsFile
* f
,
157 const gchar
* format
,
162 g_return_if_fail (f
!= NULL
);
163 g_return_if_fail (format
!= NULL
);
165 va_start (args
, format
);
166 gts_file_verror (f
, format
, args
);
170 static gint
next_char (GtsFile
* f
)
173 return fgetc (f
->fp
);
174 else if (*f
->s
== '\0')
183 * Returns: the next character in @f or EOF if the end of the file is
184 * reached or if an error occured.
186 gint
gts_file_getc (GtsFile
* f
)
190 g_return_val_if_fail (f
!= NULL
, EOF
);
192 if (f
->type
== GTS_ERROR
)
197 while (char_in_string (c
, f
->comments
)) {
198 while (c
!= EOF
&& c
!= '\n')
216 f
->line
= f
->curline
;
217 f
->pos
= f
->curpos
- 1;
218 gts_file_error (f
, "no matching opening brace");
231 * @size: size of an element.
232 * @nmemb: number of elements.
234 * Reads @nmemb elements of data, each @size bytes long, from @f,
235 * storing them at the location given by @ptr.
237 * Returns: the number of elements read.
239 guint
gts_file_read (GtsFile
* f
, gpointer ptr
, guint size
, guint nmemb
)
244 g_return_val_if_fail (f
!= NULL
, 0);
245 g_return_val_if_fail (ptr
!= NULL
, 0);
246 g_return_val_if_fail (f
->fp
!= NULL
, 0);
248 if (f
->type
== GTS_ERROR
)
251 n
= fread (ptr
, size
, nmemb
, f
->fp
);
252 for (i
= 0, p
= ptr
; i
< n
*size
; i
++, p
++) {
263 * gts_file_getc_scope :
266 * Returns: the next character in @f in the scope defined by
267 * @f->scope_max or EOF if the end of the file is reached or if an
270 gint
gts_file_getc_scope (GtsFile
* f
)
274 g_return_val_if_fail (f
!= NULL
, EOF
);
276 if (f
->type
== GTS_ERROR
)
279 if (f
->scope
<= f
->scope_max
)
280 c
= gts_file_getc (f
);
282 c
= gts_file_getc (f
);
283 while (c
!= EOF
&& f
->scope
> f
->scope_max
)
284 c
= gts_file_getc (f
);
290 * gts_file_next_token:
293 * Reads next token from @f and updates its @token and @delim fields.
295 void gts_file_next_token (GtsFile
* f
)
298 gboolean in_string
= FALSE
;
300 g_return_if_fail (f
!= NULL
);
302 if (f
->type
== GTS_ERROR
)
304 f
->token
->str
[0] = '\0';
306 if (f
->next_token
!= '\0') {
307 if (char_in_string (f
->next_token
, f
->tokens
)) {
308 f
->line
= f
->curline
;
309 f
->pos
= f
->curpos
- 1;
310 g_string_append_c (f
->token
, f
->next_token
);
311 f
->type
= f
->next_token
;
312 f
->next_token
= '\0';
317 f
->next_token
= '\0';
321 c
= gts_file_getc_scope (f
);
323 while (c
!= EOF
&& (!in_string
|| !char_in_string (c
, f
->delimiters
))) {
325 if (char_in_string (c
, f
->tokens
)) {
329 g_string_append_c (f
->token
, c
);
331 else if (!char_in_string (c
, f
->delimiters
)) {
333 f
->line
= f
->curline
;
334 f
->pos
= f
->curpos
- 1;
335 g_string_append_c (f
->token
, c
);
336 if (char_in_string (c
, f
->tokens
)) {
341 c
= gts_file_getc_scope (f
);
343 if (f
->type
== GTS_NONE
&& f
->token
->len
> 0) {
347 while (*a
!= '\0' && char_in_string (*a
, "+-")) a
++;
349 f
->type
= GTS_STRING
;
353 while (*a
!= '\0' && char_in_string (*a
, "+-0123456789")) a
++;
359 while (*a
!= '\0' && char_in_string (*a
, "+-eE.")) a
++;
361 f
->type
= GTS_STRING
;
365 while (*a
!= '\0' && char_in_string (*a
, "+-0123456789eE.")) a
++;
371 if (!strncmp (a
, "0x", 2) ||
372 !strncmp (a
, "-0x", 3) ||
373 !strncmp (a
, "+0x", 3)) {
374 while (*a
!= '\0' && char_in_string (*a
, "+-0123456789abcdefx")) a
++;
380 while (*a
!= '\0' && char_in_string (*a
, "+-0123456789abcdefx.p")) a
++;
386 f
->type
= GTS_STRING
;
391 * gts_file_first_token_after:
393 * @type: a #GtsTokenType.
395 * Finds and sets the first token of a type different from @type
396 * occuring after a token of type @type.
398 void gts_file_first_token_after (GtsFile
* f
, GtsTokenType type
)
400 g_return_if_fail (f
!= NULL
);
402 while (f
->type
!= GTS_ERROR
&&
403 f
->type
!= GTS_NONE
&&
405 gts_file_next_token (f
);
406 while (f
->type
== type
)
407 gts_file_next_token (f
);
411 * gts_file_assign_start:
413 * @vars: a %GTS_NONE terminated array of #GtsFileVariable.
415 * Opens a block delimited by braces to read a list of optional
416 * arguments specified by @vars.
418 * If an error is encountered the @error field of @f is set.
420 void gts_file_assign_start (GtsFile
* f
, GtsFileVariable
* vars
)
422 GtsFileVariable
* var
;
424 g_return_if_fail (f
!= NULL
);
425 g_return_if_fail (vars
!= NULL
);
428 while (var
->type
!= GTS_NONE
)
429 (var
++)->set
= FALSE
;
431 if (f
->type
!= '{') {
432 gts_file_error (f
, "expecting an opening brace");
437 gts_file_next_token (f
);
441 * gts_file_assign_next:
443 * @vars: a %GTS_NONE terminated array of #GtsFileVariable.
445 * Assigns the next optional argument of @vars read from @f.
447 * Returns: the variable of @vars which has been assigned or %NULL if
448 * no variable has been assigned (if an error has been encountered the
449 * @error field of @f is set).
451 GtsFileVariable
* gts_file_assign_next (GtsFile
* f
, GtsFileVariable
* vars
)
453 GtsFileVariable
* var
;
454 gboolean found
= FALSE
;
456 g_return_val_if_fail (f
!= NULL
, NULL
);
457 g_return_val_if_fail (vars
!= NULL
, NULL
);
459 while (f
->type
== '\n')
460 gts_file_next_token (f
);
461 if (f
->type
== '}') {
463 gts_file_next_token (f
);
466 if (f
->type
== GTS_ERROR
)
470 while (f
->type
!= GTS_ERROR
&& var
->type
!= GTS_NONE
&& !found
) {
471 if (!strcmp (var
->name
, f
->token
->str
)) {
473 if (var
->unique
&& var
->set
)
474 gts_file_error (f
, "variable `%s' was already set at line %d:%d",
475 var
->name
, var
->line
, var
->pos
);
479 gts_file_next_token (f
);
481 gts_file_error (f
, "expecting `='");
488 gts_file_next_token (f
);
489 if (f
->type
!= GTS_INT
) {
490 gts_file_error (f
, "expecting an integer");
494 *((gint
*) var
->data
) = atoi (f
->token
->str
);
497 gts_file_next_token (f
);
498 if (f
->type
!= GTS_INT
) {
499 gts_file_error (f
, "expecting an integer");
503 *((guint
*) var
->data
) = atoi (f
->token
->str
);
506 gts_file_next_token (f
);
507 if (f
->type
!= GTS_INT
&& f
->type
!= GTS_FLOAT
) {
508 gts_file_error (f
, "expecting a number");
512 *((gfloat
*) var
->data
) = atof (f
->token
->str
);
515 gts_file_next_token (f
);
516 if (f
->type
!= GTS_INT
&& f
->type
!= GTS_FLOAT
) {
517 gts_file_error (f
, "expecting a number");
521 *((gdouble
*) var
->data
) = atof (f
->token
->str
);
524 gts_file_next_token (f
);
525 if (f
->type
!= GTS_INT
&&
526 f
->type
!= GTS_FLOAT
&&
527 f
->type
!= GTS_STRING
) {
528 gts_file_error (f
, "expecting a string");
532 *((gchar
**) var
->data
) = g_strdup (f
->token
->str
);
535 g_assert_not_reached ();
544 gts_file_error (f
, "unknown identifier `%s'", f
->token
->str
);
545 else if (f
->type
!= GTS_ERROR
) {
547 gts_file_next_token (f
);
554 * gts_file_assign_variables:
556 * @vars: an array of #GtsFileVariable.
558 * Assigns all the variables belonging to @vars found in @f.
560 * If an error is encountered the @error field of @f is set.
562 void gts_file_assign_variables (GtsFile
* f
, GtsFileVariable
* vars
)
564 g_return_if_fail (f
!= NULL
);
565 g_return_if_fail (vars
!= NULL
);
567 gts_file_assign_start (f
, vars
);
568 while (gts_file_assign_next (f
, vars
))
573 * gts_file_variable_error:
575 * @vars: an array of #GtsFileVariable.
576 * @name: the name of a variable in @vars.
577 * @format: the standard sprintf() format string.
578 * @...: the parameters to insert into the format string.
580 * Sets the @error field of @f using gts_file_verror().
582 * String @name must match one of the variable names in @vars.
584 * If variable @name has been assigned (using gts_file_assign_variables())
585 * sets the @line and @pos fields of @f to the line and position where
586 * it has been assigned.
588 void gts_file_variable_error (GtsFile
* f
,
589 GtsFileVariable
* vars
,
591 const gchar
* format
,
595 GtsFileVariable
* var
;
597 g_return_if_fail (f
!= NULL
);
598 g_return_if_fail (vars
!= NULL
);
599 g_return_if_fail (name
!= NULL
);
600 g_return_if_fail (format
!= NULL
);
603 while (var
->type
!= GTS_NONE
&& strcmp (var
->name
, name
))
606 g_return_if_fail (var
->type
!= GTS_NONE
); /* @name not found in @vars */
613 va_start (args
, format
);
614 gts_file_verror (f
, format
, args
);
618 #ifdef DEBUG_FUNCTIONS
619 static GHashTable
* ids
= NULL
;
620 static guint next_id
= 1;
622 guint
id (gpointer p
)
624 g_return_val_if_fail (p
!= NULL
, 0);
625 g_return_val_if_fail (ids
!= NULL
, 0);
626 g_assert (g_hash_table_lookup (ids
, p
));
627 return GPOINTER_TO_UINT (g_hash_table_lookup (ids
, p
));
630 void id_insert (gpointer p
)
632 g_return_if_fail (p
!= NULL
);
633 if (ids
== NULL
) ids
= g_hash_table_new (NULL
, NULL
);
634 g_assert (g_hash_table_lookup (ids
, p
) == NULL
);
635 g_hash_table_insert (ids
, p
, GUINT_TO_POINTER (next_id
++));
638 void id_remove (gpointer p
)
640 g_assert (g_hash_table_lookup (ids
, p
));
641 g_hash_table_remove (ids
, p
);
644 void gts_write_triangle (GtsTriangle
* t
,
648 gdouble xo
= o
? o
->x
: 0.0;
649 gdouble yo
= o
? o
->y
: 0.0;
650 gdouble zo
= o
? o
->z
: 0.0;
652 g_return_if_fail (t
!= NULL
&& fptr
!= NULL
);
654 fprintf (fptr
, "(hdefine geometry \"t%d\" { =\n", id (t
));
655 fprintf (fptr
, "OFF 3 1 0\n"
656 "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n"
657 "(geometry \"t%d\" { : \"t%d\"})\n"
658 "(normalization \"t%d\" none)\n",
659 GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
)->x
- xo
,
660 GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
)->y
- yo
,
661 GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
)->z
- zo
,
662 GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
)->x
- xo
,
663 GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
)->y
- yo
,
664 GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
)->z
- zo
,
665 GTS_POINT (gts_triangle_vertex (t
))->x
- xo
,
666 GTS_POINT (gts_triangle_vertex (t
))->y
- yo
,
667 GTS_POINT (gts_triangle_vertex (t
))->z
- zo
,
668 id (t
), id (t
), id (t
));
671 void gts_write_segment (GtsSegment
* s
,
675 gdouble xo
= o
? o
->x
: 0.0;
676 gdouble yo
= o
? o
->y
: 0.0;
677 gdouble zo
= o
? o
->z
: 0.0;
679 g_return_if_fail (s
!= NULL
&& fptr
!= NULL
);
681 fprintf (fptr
, "(geometry \"s%d\" { =\n", id (s
));
682 fprintf (fptr
, "VECT 1 2 0 2 0 %g %g %g %g %g %g })\n"
683 "(normalization \"s%d\" none)\n",
684 GTS_POINT (s
->v1
)->x
- xo
,
685 GTS_POINT (s
->v1
)->y
- yo
,
686 GTS_POINT (s
->v1
)->z
- zo
,
687 GTS_POINT (s
->v2
)->x
- xo
,
688 GTS_POINT (s
->v2
)->y
- yo
,
689 GTS_POINT (s
->v2
)->z
- zo
,
692 #endif /* DEBUG_FUNCTIONS */