pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* GTS - Library for the manipulation of triangulated surfaces 00002 * Copyright (C) 1999 Stéphane Popinet 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Library General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Library General Public 00015 * License along with this library; if not, write to the 00016 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 * Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <string.h> 00022 00023 #include "gts.h" 00024 #include "gts-private.h" 00025 #include "config.h" 00026 00027 const guint gts_major_version = GTS_MAJOR_VERSION; 00028 const guint gts_minor_version = GTS_MINOR_VERSION; 00029 const guint gts_micro_version = GTS_MICRO_VERSION; 00030 const guint gts_interface_age = 1; 00031 const guint gts_binary_age = 1; 00032 00033 static gboolean char_in_string (char c, const char * s) 00034 { 00035 while (*s != '\0') 00036 if (*(s++) == c) 00037 return TRUE; 00038 return FALSE; 00039 } 00040 00041 static GtsFile * file_new (void) 00042 { 00043 GtsFile * f; 00044 00045 f = g_malloc (sizeof (GtsFile)); 00046 f->fp = NULL; 00047 f->s = f->s1 = NULL; 00048 f->curline = 1; 00049 f->curpos = 1; 00050 f->token = g_string_new (""); 00051 f->type = '\0'; 00052 f->error = NULL; 00053 f->next_token = '\0'; 00054 00055 f->scope = f->scope_max = 0; 00056 f->delimiters = g_strdup (" \t"); 00057 f->comments = g_strdup (GTS_COMMENTS); 00058 f->tokens = g_strdup ("\n{}()="); 00059 00060 return f; 00061 } 00062 00069 GtsFile * gts_file_new (FILE * fp) 00070 { 00071 GtsFile * f; 00072 00073 g_return_val_if_fail (fp != NULL, NULL); 00074 00075 f = file_new (); 00076 f->fp = fp; 00077 gts_file_next_token (f); 00078 00079 return f; 00080 } 00081 00088 GtsFile * gts_file_new_from_string (const gchar * s) 00089 { 00090 GtsFile * f; 00091 00092 g_return_val_if_fail (s != NULL, NULL); 00093 00094 f = file_new (); 00095 f->s1 = f->s = g_strdup (s); 00096 gts_file_next_token (f); 00097 00098 return f; 00099 } 00100 00107 void gts_file_destroy (GtsFile * f) 00108 { 00109 g_return_if_fail (f != NULL); 00110 00111 g_free (f->delimiters); 00112 g_free (f->comments); 00113 g_free (f->tokens); 00114 if (f->error) 00115 g_free (f->error); 00116 if (f->s1) 00117 g_free (f->s1); 00118 g_string_free (f->token, TRUE); 00119 g_free (f); 00120 } 00121 00133 void gts_file_verror (GtsFile * f, 00134 const gchar * format, 00135 va_list args) 00136 { 00137 g_return_if_fail (f != NULL); 00138 g_return_if_fail (format != NULL); 00139 00140 g_assert (f->type != GTS_ERROR); 00141 f->error = g_strdup_vprintf (format, args); 00142 f->type = GTS_ERROR; 00143 } 00144 00156 void gts_file_error (GtsFile * f, 00157 const gchar * format, 00158 ...) 00159 { 00160 va_list args; 00161 00162 g_return_if_fail (f != NULL); 00163 g_return_if_fail (format != NULL); 00164 00165 va_start (args, format); 00166 gts_file_verror (f, format, args); 00167 va_end (args); 00168 } 00169 00170 static gint next_char (GtsFile * f) 00171 { 00172 if (f->fp) 00173 return fgetc (f->fp); 00174 else if (*f->s == '\0') 00175 return EOF; 00176 return *(f->s++); 00177 } 00178 00186 gint gts_file_getc (GtsFile * f) 00187 { 00188 gint c; 00189 00190 g_return_val_if_fail (f != NULL, EOF); 00191 00192 if (f->type == GTS_ERROR) 00193 return EOF; 00194 00195 c = next_char (f); 00196 f->curpos++; 00197 while (char_in_string (c, f->comments)) { 00198 while (c != EOF && c != '\n') 00199 c = next_char (f); 00200 if (c == '\n') { 00201 f->curline++; 00202 f->curpos = 1; 00203 c = next_char (f); 00204 } 00205 } 00206 switch (c) { 00207 case '\n': 00208 f->curline++; 00209 f->curpos = 1; 00210 break; 00211 case '{': 00212 f->scope++; 00213 break; 00214 case '}': 00215 if (f->scope == 0) { 00216 f->line = f->curline; 00217 f->pos = f->curpos - 1; 00218 gts_file_error (f, "no matching opening brace"); 00219 c = EOF; 00220 } 00221 else 00222 f->scope--; 00223 } 00224 return c; 00225 } 00226 00239 guint gts_file_read (GtsFile * f, gpointer ptr, guint size, guint nmemb) 00240 { 00241 guint i, n; 00242 gchar * p; 00243 00244 g_return_val_if_fail (f != NULL, 0); 00245 g_return_val_if_fail (ptr != NULL, 0); 00246 g_return_val_if_fail (f->fp != NULL, 0); 00247 00248 if (f->type == GTS_ERROR) 00249 return 0; 00250 00251 n = fread (ptr, size, nmemb, f->fp); 00252 for (i = 0, p = ptr; i < n*size; i++, p++) { 00253 f->curpos++; 00254 if (*p == '\n') { 00255 f->curline++; 00256 f->curpos = 1; 00257 } 00258 } 00259 return n; 00260 } 00261 00270 gint gts_file_getc_scope (GtsFile * f) 00271 { 00272 gint c; 00273 00274 g_return_val_if_fail (f != NULL, EOF); 00275 00276 if (f->type == GTS_ERROR) 00277 return EOF; 00278 00279 if (f->scope <= f->scope_max) 00280 c = gts_file_getc (f); 00281 else { 00282 c = gts_file_getc (f); 00283 while (c != EOF && f->scope > f->scope_max) 00284 c = gts_file_getc (f); 00285 } 00286 return c; 00287 } 00288 00295 void gts_file_next_token (GtsFile * f) 00296 { 00297 gint c; 00298 gboolean in_string = FALSE; 00299 00300 g_return_if_fail (f != NULL); 00301 00302 if (f->type == GTS_ERROR) 00303 return; 00304 f->token->str[0] = '\0'; 00305 f->token->len = 0; 00306 if (f->next_token != '\0') { 00307 if (char_in_string (f->next_token, f->tokens)) { 00308 f->line = f->curline; 00309 f->pos = f->curpos - 1; 00310 g_string_append_c (f->token, f->next_token); 00311 f->type = f->next_token; 00312 f->next_token = '\0'; 00313 return; 00314 } 00315 else { 00316 c = f->next_token; 00317 f->next_token = '\0'; 00318 } 00319 } 00320 else 00321 c = gts_file_getc_scope (f); 00322 f->type = GTS_NONE; 00323 while (c != EOF && (!in_string || !char_in_string (c, f->delimiters))) { 00324 if (in_string) { 00325 if (char_in_string (c, f->tokens)) { 00326 f->next_token = c; 00327 break; 00328 } 00329 g_string_append_c (f->token, c); 00330 } 00331 else if (!char_in_string (c, f->delimiters)) { 00332 in_string = TRUE; 00333 f->line = f->curline; 00334 f->pos = f->curpos - 1; 00335 g_string_append_c (f->token, c); 00336 if (char_in_string (c, f->tokens)) { 00337 f->type = c; 00338 break; 00339 } 00340 } 00341 c = gts_file_getc_scope (f); 00342 } 00343 if (f->type == GTS_NONE && f->token->len > 0) { 00344 gchar * a; 00345 00346 a = f->token->str; 00347 while (*a != '\0' && char_in_string (*a, "+-")) a++; 00348 if (*a == '\0') { 00349 f->type = GTS_STRING; 00350 return; 00351 } 00352 a = f->token->str; 00353 while (*a != '\0' && char_in_string (*a, "+-0123456789")) a++; 00354 if (*a == '\0') { 00355 f->type = GTS_INT; 00356 return; 00357 } 00358 a = f->token->str; 00359 while (*a != '\0' && char_in_string (*a, "+-eE.")) a++; 00360 if (*a == '\0') { 00361 f->type = GTS_STRING; 00362 return; 00363 } 00364 a = f->token->str; 00365 while (*a != '\0' && char_in_string (*a, "+-0123456789eE.")) a++; 00366 if (*a == '\0') { 00367 f->type = GTS_FLOAT; 00368 return; 00369 } 00370 a = f->token->str; 00371 if (!strncmp (a, "0x", 2) || 00372 !strncmp (a, "-0x", 3) || 00373 !strncmp (a, "+0x", 3)) { 00374 while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx")) a++; 00375 if (*a == '\0') { 00376 f->type = GTS_INT; 00377 return; 00378 } 00379 a = f->token->str; 00380 while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx.p")) a++; 00381 if (*a == '\0') { 00382 f->type = GTS_FLOAT; 00383 return; 00384 } 00385 } 00386 f->type = GTS_STRING; 00387 } 00388 } 00389 00398 void gts_file_first_token_after (GtsFile * f, GtsTokenType type) 00399 { 00400 g_return_if_fail (f != NULL); 00401 00402 while (f->type != GTS_ERROR && 00403 f->type != GTS_NONE && 00404 f->type != type) 00405 gts_file_next_token (f); 00406 while (f->type == type) 00407 gts_file_next_token (f); 00408 } 00409 00420 void gts_file_assign_start (GtsFile * f, GtsFileVariable * vars) 00421 { 00422 GtsFileVariable * var; 00423 00424 g_return_if_fail (f != NULL); 00425 g_return_if_fail (vars != NULL); 00426 00427 var = vars; 00428 while (var->type != GTS_NONE) 00429 (var++)->set = FALSE; 00430 00431 if (f->type != '{') { 00432 gts_file_error (f, "expecting an opening brace"); 00433 return; 00434 } 00435 00436 f->scope_max++; 00437 gts_file_next_token (f); 00438 } 00439 00451 GtsFileVariable * gts_file_assign_next (GtsFile * f, GtsFileVariable * vars) 00452 { 00453 GtsFileVariable * var; 00454 gboolean found = FALSE; 00455 00456 g_return_val_if_fail (f != NULL, NULL); 00457 g_return_val_if_fail (vars != NULL, NULL); 00458 00459 while (f->type == '\n') 00460 gts_file_next_token (f); 00461 if (f->type == '}') { 00462 f->scope_max--; 00463 gts_file_next_token (f); 00464 return NULL; 00465 } 00466 if (f->type == GTS_ERROR) 00467 return NULL; 00468 00469 var = vars; 00470 while (f->type != GTS_ERROR && var->type != GTS_NONE && !found) { 00471 if (!strcmp (var->name, f->token->str)) { 00472 found = TRUE; 00473 if (var->unique && var->set) 00474 gts_file_error (f, "variable `%s' was already set at line %d:%d", 00475 var->name, var->line, var->pos); 00476 else { 00477 var->line = f->line; 00478 var->pos = f->pos; 00479 gts_file_next_token (f); 00480 if (f->type != '=') 00481 gts_file_error (f, "expecting `='"); 00482 else { 00483 var->set = TRUE; 00484 switch (var->type) { 00485 case GTS_FILE: 00486 break; 00487 case GTS_INT: 00488 gts_file_next_token (f); 00489 if (f->type != GTS_INT) { 00490 gts_file_error (f, "expecting an integer"); 00491 var->set = FALSE; 00492 } 00493 else if (var->data) 00494 *((gint *) var->data) = atoi (f->token->str); 00495 break; 00496 case GTS_UINT: 00497 gts_file_next_token (f); 00498 if (f->type != GTS_INT) { 00499 gts_file_error (f, "expecting an integer"); 00500 var->set = FALSE; 00501 } 00502 else if (var->data) 00503 *((guint *) var->data) = atoi (f->token->str); 00504 break; 00505 case GTS_FLOAT: 00506 gts_file_next_token (f); 00507 if (f->type != GTS_INT && f->type != GTS_FLOAT) { 00508 gts_file_error (f, "expecting a number"); 00509 var->set = FALSE; 00510 } 00511 else if (var->data) 00512 *((gfloat *) var->data) = atof (f->token->str); 00513 break; 00514 case GTS_DOUBLE: 00515 gts_file_next_token (f); 00516 if (f->type != GTS_INT && f->type != GTS_FLOAT) { 00517 gts_file_error (f, "expecting a number"); 00518 var->set = FALSE; 00519 } 00520 else if (var->data) 00521 *((gdouble *) var->data) = atof (f->token->str); 00522 break; 00523 case GTS_STRING: 00524 gts_file_next_token (f); 00525 if (f->type != GTS_INT && 00526 f->type != GTS_FLOAT && 00527 f->type != GTS_STRING) { 00528 gts_file_error (f, "expecting a string"); 00529 var->set = FALSE; 00530 } 00531 else if (var->data) 00532 *((gchar **) var->data) = g_strdup (f->token->str); 00533 break; 00534 default: 00535 g_assert_not_reached (); 00536 } 00537 } 00538 } 00539 } 00540 else 00541 var++; 00542 } 00543 if (!found) 00544 gts_file_error (f, "unknown identifier `%s'", f->token->str); 00545 else if (f->type != GTS_ERROR) { 00546 g_assert (var->set); 00547 gts_file_next_token (f); 00548 return var; 00549 } 00550 return NULL; 00551 } 00552 00562 void gts_file_assign_variables (GtsFile * f, GtsFileVariable * vars) 00563 { 00564 g_return_if_fail (f != NULL); 00565 g_return_if_fail (vars != NULL); 00566 00567 gts_file_assign_start (f, vars); 00568 while (gts_file_assign_next (f, vars)) 00569 ; 00570 } 00571 00588 void gts_file_variable_error (GtsFile * f, 00589 GtsFileVariable * vars, 00590 const gchar * name, 00591 const gchar * format, 00592 ...) 00593 { 00594 va_list args; 00595 GtsFileVariable * var; 00596 00597 g_return_if_fail (f != NULL); 00598 g_return_if_fail (vars != NULL); 00599 g_return_if_fail (name != NULL); 00600 g_return_if_fail (format != NULL); 00601 00602 var = vars; 00603 while (var->type != GTS_NONE && strcmp (var->name, name)) 00604 var++; 00605 00606 g_return_if_fail (var->type != GTS_NONE); /* @name not found in @vars */ 00607 00608 if (var->set) { 00609 f->line = var->line; 00610 f->pos = var->pos; 00611 } 00612 00613 va_start (args, format); 00614 gts_file_verror (f, format, args); 00615 va_end (args); 00616 } 00617 00618 #ifdef DEBUG_FUNCTIONS 00619 static GHashTable * ids = NULL; 00620 static guint next_id = 1; 00621 00622 guint id (gpointer p) 00623 { 00624 g_return_val_if_fail (p != NULL, 0); 00625 g_return_val_if_fail (ids != NULL, 0); 00626 g_assert (g_hash_table_lookup (ids, p)); 00627 return GPOINTER_TO_UINT (g_hash_table_lookup (ids, p)); 00628 } 00629 00630 void id_insert (gpointer p) 00631 { 00632 g_return_if_fail (p != NULL); 00633 if (ids == NULL) ids = g_hash_table_new (NULL, NULL); 00634 g_assert (g_hash_table_lookup (ids, p) == NULL); 00635 g_hash_table_insert (ids, p, GUINT_TO_POINTER (next_id++)); 00636 } 00637 00638 void id_remove (gpointer p) 00639 { 00640 g_assert (g_hash_table_lookup (ids, p)); 00641 g_hash_table_remove (ids, p); 00642 } 00643 00644 void gts_write_triangle (GtsTriangle * t, 00645 GtsPoint * o, 00646 FILE * fptr) 00647 { 00648 gdouble xo = o ? o->x : 0.0; 00649 gdouble yo = o ? o->y : 0.0; 00650 gdouble zo = o ? o->z : 0.0; 00651 00652 g_return_if_fail (t != NULL && fptr != NULL); 00653 00654 fprintf (fptr, "(hdefine geometry \"t%d\" { =\n", id (t)); 00655 fprintf (fptr, "OFF 3 1 0\n" 00656 "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n" 00657 "(geometry \"t%d\" { : \"t%d\"})\n" 00658 "(normalization \"t%d\" none)\n", 00659 GTS_POINT (GTS_SEGMENT (t->e1)->v1)->x - xo, 00660 GTS_POINT (GTS_SEGMENT (t->e1)->v1)->y - yo, 00661 GTS_POINT (GTS_SEGMENT (t->e1)->v1)->z - zo, 00662 GTS_POINT (GTS_SEGMENT (t->e1)->v2)->x - xo, 00663 GTS_POINT (GTS_SEGMENT (t->e1)->v2)->y - yo, 00664 GTS_POINT (GTS_SEGMENT (t->e1)->v2)->z - zo, 00665 GTS_POINT (gts_triangle_vertex (t))->x - xo, 00666 GTS_POINT (gts_triangle_vertex (t))->y - yo, 00667 GTS_POINT (gts_triangle_vertex (t))->z - zo, 00668 id (t), id (t), id (t)); 00669 } 00670 00671 void gts_write_segment (GtsSegment * s, 00672 GtsPoint * o, 00673 FILE * fptr) 00674 { 00675 gdouble xo = o ? o->x : 0.0; 00676 gdouble yo = o ? o->y : 0.0; 00677 gdouble zo = o ? o->z : 0.0; 00678 00679 g_return_if_fail (s != NULL && fptr != NULL); 00680 00681 fprintf (fptr, "(geometry \"s%d\" { =\n", id (s)); 00682 fprintf (fptr, "VECT 1 2 0 2 0 %g %g %g %g %g %g })\n" 00683 "(normalization \"s%d\" none)\n", 00684 GTS_POINT (s->v1)->x - xo, 00685 GTS_POINT (s->v1)->y - yo, 00686 GTS_POINT (s->v1)->z - zo, 00687 GTS_POINT (s->v2)->x - xo, 00688 GTS_POINT (s->v2)->y - yo, 00689 GTS_POINT (s->v2)->z - zo, 00690 id (s)); 00691 } 00692 #endif /* DEBUG_FUNCTIONS */