pcb 4.1.1
An interactive printed circuit board layout editor.

gts/misc.c

Go to the documentation of this file.
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 */