hid/common/hidgl.c: Add support for rendering "fullpoly" polygons
[geda-pcb/pcjc2.git] / gts / misc.c
blob393ba06bbe924dc4609dfdb5a4a6a6fa19d79e51
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.
20 #include <stdlib.h>
21 #include <string.h>
23 #include "gts.h"
24 #include "gts-private.h"
25 #include "config.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)
35 while (*s != '\0')
36 if (*(s++) == c)
37 return TRUE;
38 return FALSE;
41 static GtsFile * file_new (void)
43 GtsFile * f;
45 f = g_malloc (sizeof (GtsFile));
46 f->fp = NULL;
47 f->s = f->s1 = NULL;
48 f->curline = 1;
49 f->curpos = 1;
50 f->token = g_string_new ("");
51 f->type = '\0';
52 f->error = NULL;
53 f->next_token = '\0';
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{}()=");
60 return f;
63 /**
64 * gts_file_new:
65 * @fp: a file pointer.
67 * Returns: a new #GtsFile.
69 GtsFile * gts_file_new (FILE * fp)
71 GtsFile * f;
73 g_return_val_if_fail (fp != NULL, NULL);
75 f = file_new ();
76 f->fp = fp;
77 gts_file_next_token (f);
79 return f;
82 /**
83 * gts_file_new_from_string:
84 * @s: a string.
86 * Returns: a new #GtsFile.
88 GtsFile * gts_file_new_from_string (const gchar * s)
90 GtsFile * f;
92 g_return_val_if_fail (s != NULL, NULL);
94 f = file_new ();
95 f->s1 = f->s = g_strdup (s);
96 gts_file_next_token (f);
98 return f;
102 * gts_file_destroy:
103 * @f: a #GtsFile.
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);
113 g_free (f->tokens);
114 if (f->error)
115 g_free (f->error);
116 if (f->s1)
117 g_free (f->s1);
118 g_string_free (f->token, TRUE);
119 g_free (f);
123 * gts_file_verror:
124 * @f: a @GtsFile.
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,
135 va_list args)
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);
142 f->type = GTS_ERROR;
146 * gts_file_error:
147 * @f: a @GtsFile.
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,
158 ...)
160 va_list args;
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);
167 va_end (args);
170 static gint next_char (GtsFile * f)
172 if (f->fp)
173 return fgetc (f->fp);
174 else if (*f->s == '\0')
175 return EOF;
176 return *(f->s++);
180 * gts_file_getc :
181 * @f: a #GtsFile.
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)
188 gint c;
190 g_return_val_if_fail (f != NULL, EOF);
192 if (f->type == GTS_ERROR)
193 return EOF;
195 c = next_char (f);
196 f->curpos++;
197 while (char_in_string (c, f->comments)) {
198 while (c != EOF && c != '\n')
199 c = next_char (f);
200 if (c == '\n') {
201 f->curline++;
202 f->curpos = 1;
203 c = next_char (f);
206 switch (c) {
207 case '\n':
208 f->curline++;
209 f->curpos = 1;
210 break;
211 case '{':
212 f->scope++;
213 break;
214 case '}':
215 if (f->scope == 0) {
216 f->line = f->curline;
217 f->pos = f->curpos - 1;
218 gts_file_error (f, "no matching opening brace");
219 c = EOF;
221 else
222 f->scope--;
224 return c;
228 * gts_file_read:
229 * @f: a #GtsFile.
230 * @ptr: a pointer.
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)
241 guint i, n;
242 gchar * p;
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)
249 return 0;
251 n = fread (ptr, size, nmemb, f->fp);
252 for (i = 0, p = ptr; i < n*size; i++, p++) {
253 f->curpos++;
254 if (*p == '\n') {
255 f->curline++;
256 f->curpos = 1;
259 return n;
263 * gts_file_getc_scope :
264 * @f: a #GtsFile.
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
268 * error occured.
270 gint gts_file_getc_scope (GtsFile * f)
272 gint c;
274 g_return_val_if_fail (f != NULL, EOF);
276 if (f->type == GTS_ERROR)
277 return EOF;
279 if (f->scope <= f->scope_max)
280 c = gts_file_getc (f);
281 else {
282 c = gts_file_getc (f);
283 while (c != EOF && f->scope > f->scope_max)
284 c = gts_file_getc (f);
286 return c;
290 * gts_file_next_token:
291 * @f: a #GtsFile.
293 * Reads next token from @f and updates its @token and @delim fields.
295 void gts_file_next_token (GtsFile * f)
297 gint c;
298 gboolean in_string = FALSE;
300 g_return_if_fail (f != NULL);
302 if (f->type == GTS_ERROR)
303 return;
304 f->token->str[0] = '\0';
305 f->token->len = 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';
313 return;
315 else {
316 c = f->next_token;
317 f->next_token = '\0';
320 else
321 c = gts_file_getc_scope (f);
322 f->type = GTS_NONE;
323 while (c != EOF && (!in_string || !char_in_string (c, f->delimiters))) {
324 if (in_string) {
325 if (char_in_string (c, f->tokens)) {
326 f->next_token = c;
327 break;
329 g_string_append_c (f->token, c);
331 else if (!char_in_string (c, f->delimiters)) {
332 in_string = TRUE;
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)) {
337 f->type = c;
338 break;
341 c = gts_file_getc_scope (f);
343 if (f->type == GTS_NONE && f->token->len > 0) {
344 gchar * a;
346 a = f->token->str;
347 while (*a != '\0' && char_in_string (*a, "+-")) a++;
348 if (*a == '\0') {
349 f->type = GTS_STRING;
350 return;
352 a = f->token->str;
353 while (*a != '\0' && char_in_string (*a, "+-0123456789")) a++;
354 if (*a == '\0') {
355 f->type = GTS_INT;
356 return;
358 a = f->token->str;
359 while (*a != '\0' && char_in_string (*a, "+-eE.")) a++;
360 if (*a == '\0') {
361 f->type = GTS_STRING;
362 return;
364 a = f->token->str;
365 while (*a != '\0' && char_in_string (*a, "+-0123456789eE.")) a++;
366 if (*a == '\0') {
367 f->type = GTS_FLOAT;
368 return;
370 a = f->token->str;
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++;
375 if (*a == '\0') {
376 f->type = GTS_INT;
377 return;
379 a = f->token->str;
380 while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx.p")) a++;
381 if (*a == '\0') {
382 f->type = GTS_FLOAT;
383 return;
386 f->type = GTS_STRING;
391 * gts_file_first_token_after:
392 * @f: a #GtsFile.
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 &&
404 f->type != type)
405 gts_file_next_token (f);
406 while (f->type == type)
407 gts_file_next_token (f);
411 * gts_file_assign_start:
412 * @f: a #GtsFile.
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);
427 var = vars;
428 while (var->type != GTS_NONE)
429 (var++)->set = FALSE;
431 if (f->type != '{') {
432 gts_file_error (f, "expecting an opening brace");
433 return;
436 f->scope_max++;
437 gts_file_next_token (f);
441 * gts_file_assign_next:
442 * @f: a #GtsFile.
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 == '}') {
462 f->scope_max--;
463 gts_file_next_token (f);
464 return NULL;
466 if (f->type == GTS_ERROR)
467 return NULL;
469 var = vars;
470 while (f->type != GTS_ERROR && var->type != GTS_NONE && !found) {
471 if (!strcmp (var->name, f->token->str)) {
472 found = TRUE;
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);
476 else {
477 var->line = f->line;
478 var->pos = f->pos;
479 gts_file_next_token (f);
480 if (f->type != '=')
481 gts_file_error (f, "expecting `='");
482 else {
483 var->set = TRUE;
484 switch (var->type) {
485 case GTS_FILE:
486 break;
487 case GTS_INT:
488 gts_file_next_token (f);
489 if (f->type != GTS_INT) {
490 gts_file_error (f, "expecting an integer");
491 var->set = FALSE;
493 else if (var->data)
494 *((gint *) var->data) = atoi (f->token->str);
495 break;
496 case GTS_UINT:
497 gts_file_next_token (f);
498 if (f->type != GTS_INT) {
499 gts_file_error (f, "expecting an integer");
500 var->set = FALSE;
502 else if (var->data)
503 *((guint *) var->data) = atoi (f->token->str);
504 break;
505 case GTS_FLOAT:
506 gts_file_next_token (f);
507 if (f->type != GTS_INT && f->type != GTS_FLOAT) {
508 gts_file_error (f, "expecting a number");
509 var->set = FALSE;
511 else if (var->data)
512 *((gfloat *) var->data) = atof (f->token->str);
513 break;
514 case GTS_DOUBLE:
515 gts_file_next_token (f);
516 if (f->type != GTS_INT && f->type != GTS_FLOAT) {
517 gts_file_error (f, "expecting a number");
518 var->set = FALSE;
520 else if (var->data)
521 *((gdouble *) var->data) = atof (f->token->str);
522 break;
523 case GTS_STRING:
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");
529 var->set = FALSE;
531 else if (var->data)
532 *((gchar **) var->data) = g_strdup (f->token->str);
533 break;
534 default:
535 g_assert_not_reached ();
540 else
541 var++;
543 if (!found)
544 gts_file_error (f, "unknown identifier `%s'", f->token->str);
545 else if (f->type != GTS_ERROR) {
546 g_assert (var->set);
547 gts_file_next_token (f);
548 return var;
550 return NULL;
554 * gts_file_assign_variables:
555 * @f: a #GtsFile.
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:
574 * @f: a #GtsFile.
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,
590 const gchar * name,
591 const gchar * format,
592 ...)
594 va_list args;
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);
602 var = vars;
603 while (var->type != GTS_NONE && strcmp (var->name, name))
604 var++;
606 g_return_if_fail (var->type != GTS_NONE); /* @name not found in @vars */
608 if (var->set) {
609 f->line = var->line;
610 f->pos = var->pos;
613 va_start (args, format);
614 gts_file_verror (f, format, args);
615 va_end (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,
645 GtsPoint * o,
646 FILE * fptr)
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,
672 GtsPoint * o,
673 FILE * fptr)
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,
690 id (s));
692 #endif /* DEBUG_FUNCTIONS */