gsymcheck
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gsymcheck - gEDA Symbol Check 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 00019 * MA 02111-1301 USA. 00020 */ 00021 00022 #include <config.h> 00023 00024 #include <stdio.h> 00025 #ifdef HAVE_STRING_H 00026 #include <string.h> 00027 #endif 00028 #ifdef HAVE_STRINGS_H 00029 #include <strings.h> 00030 #endif 00031 #ifdef HAVE_UNISTD_H 00032 #include <unistd.h> 00033 #endif 00034 00035 #include <libgeda/libgeda.h> 00036 00037 #include "../include/struct.h" 00038 #include "../include/globals.h" 00039 #include "../include/prototype.h" 00040 00041 int 00042 s_check_all(TOPLEVEL *pr_current) 00043 { 00044 GList *iter; 00045 PAGE *p_current; 00046 int return_status=0; 00047 00048 00049 for ( iter = geda_list_get_glist( pr_current->pages ); 00050 iter != NULL; 00051 iter = g_list_next( iter ) ) { 00052 00053 p_current = (PAGE *)iter->data; 00054 00055 if (s_page_objects (p_current)) { 00056 return_status = return_status + 00057 s_check_symbol (pr_current, p_current, 00058 s_page_objects (p_current)); 00059 if (!quiet_mode) s_log_message("\n"); 00060 } 00061 } 00062 00063 return(return_status); 00064 } 00065 00066 00067 int 00068 s_check_symbol (TOPLEVEL *pr_current, PAGE *p_current, const GList *obj_list) 00069 { 00070 SYMCHECK *s_symcheck=NULL; 00071 int errors=0, warnings=0; 00072 00073 s_symcheck = s_symstruct_init(); 00074 00075 if (!quiet_mode) { 00076 s_log_message("Checking: %s\n", p_current->page_filename); 00077 } 00078 00079 /* overal symbol structure test */ 00080 s_check_symbol_structure (obj_list, s_symcheck); 00081 00082 /* test all text elements */ 00083 s_check_text (obj_list, s_symcheck); 00084 00085 /* check for graphical attribute */ 00086 s_check_graphical (obj_list, s_symcheck); 00087 00088 /* check for device attribute */ 00089 s_check_device (obj_list, s_symcheck); 00090 00091 /* check for missing attributes */ 00092 s_check_missing_attributes (obj_list, s_symcheck); 00093 00094 /* check for pintype attribute (and multiples) on all pins */ 00095 s_check_pintype (obj_list, s_symcheck); 00096 00097 /* check for pinseq attribute (and multiples) on all pins */ 00098 s_check_pinseq (obj_list, s_symcheck); 00099 00100 /* check for pinnumber attribute (and multiples) on all pins */ 00101 s_check_pinnumber (obj_list, s_symcheck); 00102 00103 /* check for whether all pins are on grid */ 00104 s_check_pin_ongrid (obj_list, s_symcheck); 00105 00106 /* check for slotdef attribute on all pins (if numslots exists) */ 00107 s_check_slotdef (obj_list, s_symcheck); 00108 00109 /* check for old pin#=# attributes */ 00110 s_check_oldpin (obj_list, s_symcheck); 00111 00112 /* check for old pin#=# attributes */ 00113 s_check_oldslot (obj_list, s_symcheck); 00114 00115 /* check for nets or buses within the symbol (completely disallowed) */ 00116 s_check_nets_buses (obj_list, s_symcheck); 00117 00118 /* check for connections with in a symbol (completely disallowed) */ 00119 s_check_connections (obj_list, s_symcheck); 00120 00121 /* now report the info/warnings/errors to the user */ 00122 if (!quiet_mode) { 00123 00124 /* done, now print out the messages */ 00125 s_symstruct_print(s_symcheck); 00126 00127 if (s_symcheck->warning_count > 0) { 00128 s_log_message("%d warnings found ", 00129 s_symcheck->warning_count); 00130 if (verbose_mode < 2) { 00131 s_log_message("(use -vv to view details)\n"); 00132 } else { 00133 s_log_message("\n"); 00134 } 00135 } 00136 00137 if (s_symcheck->error_count == 0) { 00138 s_log_message("No errors found\n"); 00139 } else if (s_symcheck->error_count == 1) { 00140 s_log_message("1 ERROR found "); 00141 if (verbose_mode < 1) { 00142 s_log_message("(use -v to view details)\n"); 00143 } else { 00144 s_log_message("\n"); 00145 } 00146 00147 } else if (s_symcheck->error_count > 1) { 00148 s_log_message("%d ERRORS found ", 00149 s_symcheck->error_count); 00150 if (verbose_mode < 1) { 00151 s_log_message("(use -v to view details)\n"); 00152 } else { 00153 s_log_message("\n"); 00154 } 00155 } 00156 } 00157 00158 errors = s_symcheck->error_count; 00159 warnings = s_symcheck->warning_count; 00160 s_symstruct_free(s_symcheck); 00161 if (errors) { 00162 return(2); 00163 } else if (warnings) { 00164 return(1); 00165 } else { 00166 return(0); 00167 } 00168 } 00169 00170 00171 gboolean 00172 s_check_list_has_item(char **list , char *item) 00173 { 00174 gint cur; 00175 for (cur = 0; list[cur] != NULL; cur++) { 00176 if (strcmp(item, list[cur]) == 0) 00177 return TRUE; 00178 } 00179 return FALSE; 00180 } 00181 00182 void 00183 s_check_symbol_structure (const GList *obj_list, SYMCHECK *s_current) 00184 { 00185 const GList *iter; 00186 00187 gchar *message; 00188 gchar **tokens; 00189 00190 char *valid_pin_attributes[] = {"pinlabel", "pintype", 00191 "pinseq", "pinnumber", 00192 NULL}; 00193 char *valid_attributes[] = {"device", "graphical", "description", 00194 "author", "comment", "numslots", 00195 "slotdef", "footprint", "documentation", 00196 "refdes", "slot", "net", "value", 00197 "symversion", "dist-license", "use-license", 00198 NULL}; 00199 char *obsolete_attributes[] = {"uref", "label", "email", 00200 NULL}; 00201 char *forbidden_attributes[] = {"type", "name", 00202 NULL}; 00203 /* pin# ?, slot# ? */ 00204 00205 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 00206 OBJECT *o_current = iter->data; 00207 00208 if (o_current->type == OBJ_TEXT) { 00209 tokens = g_strsplit(o_current->text->string,"=", 2); 00210 if (tokens[0] != NULL && tokens[1] != NULL) { 00211 if (s_check_list_has_item(forbidden_attributes, tokens[0])) { 00212 message = g_strdup_printf ("Found forbidden %s= attribute: [%s=%s]\n", 00213 tokens[0], tokens[0], tokens[1]); 00214 s_current->error_messages = 00215 g_list_append(s_current->error_messages, message); 00216 s_current->error_count++; 00217 } 00218 else if (s_check_list_has_item(obsolete_attributes, tokens[0])) { 00219 message = g_strdup_printf ("Found obsolete %s= attribute: [%s=%s]\n", 00220 tokens[0], tokens[0], tokens[1]); 00221 s_current->warning_messages = 00222 g_list_append(s_current->warning_messages, message); 00223 s_current->warning_count++; 00224 } 00225 else if (s_check_list_has_item(valid_pin_attributes, tokens[0])) { 00226 if (o_current->attached_to == NULL 00227 || o_current->attached_to->type != OBJ_PIN) { 00228 message = g_strdup_printf ("Found misplaced pin attribute:" 00229 " [%s=%s]\n", tokens[0], tokens[1]); 00230 s_current->error_messages = 00231 g_list_append(s_current->error_messages, message); 00232 s_current->error_count++; 00233 } 00234 } 00235 else if (!s_check_list_has_item(valid_attributes, tokens[0])) { 00236 message = g_strdup_printf ("Found unknown %s= attribute: [%s=%s]\n", 00237 tokens[0], tokens[0], tokens[1]); 00238 s_current->warning_messages = 00239 g_list_append(s_current->warning_messages, message); 00240 s_current->warning_count++; 00241 } 00242 else if (o_current->attached_to != NULL) { 00243 message = g_strdup_printf ("Found wrongly attached attribute: " 00244 "[%s=%s]\n", 00245 tokens[0], tokens[1]); 00246 s_current->error_messages = 00247 g_list_append(s_current->error_messages, message); 00248 s_current->error_count++; 00249 } 00250 } else { /* object is not an attribute */ 00251 if (o_current->show_name_value != SHOW_NAME_VALUE) { 00252 message = g_strdup_printf ("Found a simple text object with only SHOW_NAME" 00253 " or SHOW_VALUE set [%s]\n", 00254 o_current->text->string); 00255 s_current->warning_messages = 00256 g_list_append(s_current->warning_messages, message); 00257 s_current->warning_count++; 00258 } 00259 } 00260 g_strfreev(tokens); 00261 } 00262 } 00263 } 00264 00265 void 00266 s_check_text (const GList *obj_list, SYMCHECK *s_current) 00267 { 00268 const GList *iter; 00269 OBJECT *o_current; 00270 gboolean overbar_started, escape, leave_parser; 00271 char *message; 00272 char *text_string, *ptr; 00273 gunichar current_char; 00274 00275 for (iter = obj_list; iter != NULL; iter = g_list_next(iter)) { 00276 o_current = iter->data; 00277 00278 if (o_current->type != OBJ_TEXT) 00279 continue; 00280 00281 overbar_started = escape = leave_parser = FALSE; 00282 text_string = o_current->text->string; 00283 00284 for (ptr = text_string; 00285 ptr != NULL && !leave_parser; 00286 ptr = g_utf8_find_next_char (ptr, NULL)) { 00287 00288 current_char = g_utf8_get_char_validated (ptr, -1); 00289 00290 /* state machine to interpret the string: 00291 * there are two independant state variables overbar_started and escape. 00292 */ 00293 switch (current_char) { 00294 case '\0': 00295 /* end of the string */ 00296 leave_parser = TRUE; 00297 break; 00298 case '\\': 00299 if (escape == TRUE) { 00300 escape = FALSE; 00301 } else { 00302 escape = TRUE; 00303 } 00304 break; 00305 case '_': 00306 if (escape == TRUE) { 00307 escape = FALSE; 00308 if (overbar_started == TRUE) { 00309 overbar_started = FALSE; 00310 } else { 00311 overbar_started = TRUE; 00312 } 00313 } 00314 break; 00315 default: 00316 if (escape == TRUE) { 00317 message = g_strdup_printf ("Found text with a '\\' in it: consider" 00318 " to escape it with '\\\\' [%s]\n", 00319 text_string); 00320 s_current->warning_messages = g_list_append(s_current->warning_messages, 00321 message); 00322 s_current->warning_count++; 00323 escape = FALSE; 00324 } 00325 } 00326 } 00327 00328 if (escape == TRUE) { 00329 message = g_strdup_printf ("Found text with a trailing '\': consider to " 00330 "escape it with '\\\\' [%s]\n", 00331 text_string); 00332 s_current->warning_messages = g_list_append(s_current->warning_messages, 00333 message); 00334 s_current->warning_count++; 00335 } 00336 00337 if (overbar_started == TRUE) { 00338 message = g_strdup_printf ("Found text with unbalanced overbar " 00339 "markers '\\_' in it' [%s]\n", 00340 text_string); 00341 s_current->warning_messages = g_list_append(s_current->warning_messages, 00342 message); 00343 s_current->warning_count++; 00344 } 00345 } 00346 } 00347 00348 void 00349 s_check_graphical (const GList *obj_list, SYMCHECK *s_current) 00350 { 00351 char *temp; 00352 00353 /* look for special graphical tag */ 00354 temp = o_attrib_search_floating_attribs_by_name (obj_list, "graphical", 0); 00355 00356 if (temp) { 00357 s_current->graphical_symbol=TRUE; 00358 g_free(temp); 00359 } 00360 } 00361 00362 void 00363 s_check_device (const GList *obj_list, SYMCHECK *s_current) 00364 { 00365 char *temp; 00366 char *message; 00367 00368 /* search for device attribute */ 00369 temp = o_attrib_search_floating_attribs_by_name (obj_list, "device", 0); 00370 if (!temp) { 00371 /* did not find device= attribute */ 00372 message = g_strdup ("Missing device= attribute\n"); 00373 s_current->error_messages = g_list_append(s_current->error_messages, 00374 message); 00375 s_current->missing_device_attrib=TRUE; 00376 s_current->error_count++; 00377 } else { 00378 /* found device= attribute */ 00379 s_current->missing_device_attrib=FALSE; 00380 s_current->device_attribute = g_strdup (temp); 00381 message = g_strdup_printf ("Found device=%s\n", temp); 00382 s_current->info_messages = g_list_append(s_current->info_messages, 00383 message); 00384 } 00385 00386 /* check for device = none for graphical symbols */ 00387 if (temp && s_current->graphical_symbol && (strcmp(temp, "none") == 0)) { 00388 s_current->device_attribute_incorrect=FALSE; 00389 message = g_strdup ("Found graphical symbol, device=none\n"); 00390 s_current->info_messages = g_list_append(s_current->info_messages, 00391 message); 00392 } else if (s_current->graphical_symbol) { 00393 s_current->device_attribute_incorrect=TRUE; 00394 message = g_strdup ("Found graphical symbol, device= should be set to none\n"); 00395 s_current->warning_messages = g_list_append(s_current->warning_messages, 00396 message); 00397 s_current->warning_count++; 00398 } 00399 00400 g_free(temp); 00401 } 00402 00403 00404 void 00405 s_check_pinseq (const GList *obj_list, SYMCHECK *s_current) 00406 { 00407 char *string; 00408 int found_first=FALSE; 00409 int missing_pinseq_attrib_sum=0; 00410 int multiple_pinseq_attrib_sum=0; 00411 int counter=0; 00412 00413 GList *found_numbers = NULL; 00414 GList *ptr1 = NULL; 00415 GList *ptr2 = NULL; 00416 const GList *iter; 00417 char *number; 00418 char *message; 00419 00420 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 00421 OBJECT *o_current = iter->data; 00422 00423 if (o_current->type == OBJ_PIN) 00424 { 00425 missing_pinseq_attrib_sum = 0; 00426 multiple_pinseq_attrib_sum = 0; 00427 found_first = FALSE; 00428 counter = 0; 00429 00430 string = o_attrib_search_object_attribs_by_name (o_current, "pinseq", 00431 counter); 00432 if (!string) 00433 { 00434 message = g_strdup ("Missing pinseq= attribute\n"); 00435 s_current->error_messages = g_list_append(s_current->error_messages, 00436 message); 00437 missing_pinseq_attrib_sum++; 00438 s_current->error_count++; 00439 } 00440 00441 while (string) 00442 { 00443 00444 message = g_strdup_printf ("Found pinseq=%s attribute\n", string); 00445 s_current->info_messages = g_list_append(s_current->info_messages, 00446 message); 00447 00448 number = g_strdup (string); 00449 00450 if (strcmp(number, "0") == 0) { 00451 message = g_strdup ("Found pinseq=0 attribute\n"); 00452 s_current->error_messages = g_list_append(s_current->error_messages, 00453 message); 00454 s_current->error_count++; 00455 } 00456 00457 if (found_first) { 00458 message = g_strdup_printf ( 00459 "Found multiple pinseq=%s attributes on one pin\n", 00460 string); 00461 s_current->error_messages = g_list_append(s_current->error_messages, 00462 message); 00463 multiple_pinseq_attrib_sum++; 00464 s_current->error_count++; 00465 } 00466 00467 g_free(string); 00468 00469 /* this is the first attribute found */ 00470 if (!found_first) { 00471 found_numbers = g_list_append(found_numbers, number); 00472 found_first=TRUE; 00473 } else { 00474 g_free(number); 00475 } 00476 00477 counter++; 00478 string = o_attrib_search_object_attribs_by_name (o_current, "pinseq", 00479 counter); 00480 } 00481 00482 s_current->missing_pinseq_attrib += missing_pinseq_attrib_sum; 00483 s_current->multiple_pinseq_attrib += multiple_pinseq_attrib_sum; 00484 } 00485 00486 } 00487 00488 ptr1 = found_numbers; 00489 while (ptr1) 00490 { 00491 char *string = (char *) ptr1->data; 00492 int found = 0; 00493 00494 ptr2 = found_numbers; 00495 while(ptr2 && string) 00496 { 00497 char *current = (char *) ptr2->data; 00498 00499 if (current && strcmp(string, current) == 0) { 00500 found++; 00501 } 00502 00503 ptr2 = g_list_next(ptr2); 00504 } 00505 00506 if (found > 1) 00507 { 00508 message = g_strdup_printf ( 00509 "Found duplicate pinseq=%s attribute in the symbol\n", 00510 string); 00511 s_current->error_messages = g_list_append(s_current->error_messages, 00512 message); 00513 s_current->error_count++; 00514 s_current->duplicate_pinseq_attrib++; 00515 } 00516 00517 ptr1 = g_list_next(ptr1); 00518 } 00519 00520 ptr1 = found_numbers; 00521 while (ptr1) 00522 { 00523 g_free(ptr1->data); 00524 ptr1 = g_list_next(ptr1); 00525 } 00526 g_list_free(found_numbers); 00527 00528 } 00529 00530 00531 void 00532 s_check_pinnumber (const GList *obj_list, SYMCHECK *s_current) 00533 { 00534 char *string; 00535 int missing_pinnumber_attrib_sum=0; 00536 int multiple_pinnumber_attrib_sum=0; 00537 int counter=0; 00538 int i; 00539 00540 gchar **net_tokens; 00541 gchar **pin_tokens; 00542 GList *net_numbers = NULL; 00543 GList *pin_numbers = NULL; 00544 GList *cur = NULL; 00545 GList *cur2 = NULL; 00546 const GList *iter; 00547 char *message; 00548 char *net = NULL; 00549 00550 /* collect all net pins */ 00551 for (counter = 0; 00552 (net = o_attrib_search_floating_attribs_by_name (obj_list, "net", counter)) != NULL; 00553 counter++) { 00554 message = g_strdup_printf ("Found net=%s attribute\n", net); 00555 s_current->info_messages = g_list_append(s_current->info_messages, 00556 message); 00557 00558 net_tokens = g_strsplit(net,":", -1); 00559 /* length of net tokens have to be 2 */ 00560 if (net_tokens[1] == NULL) { 00561 message = g_strdup_printf ("Bad net= attribute [net=%s]\n", net); 00562 s_current->error_messages = g_list_append(s_current->error_messages, 00563 message); 00564 s_current->error_count++; 00565 g_strfreev(net_tokens); 00566 continue; 00567 } else if (net_tokens[2] != NULL) { /* more than 2 tokens */ 00568 message = g_strdup_printf ("Bad net= attribute [net=%s]\n", net); 00569 s_current->error_messages = g_list_append(s_current->error_messages, 00570 message); 00571 s_current->error_count++; 00572 g_strfreev(net_tokens); 00573 continue; 00574 } 00575 00576 pin_tokens = g_strsplit(net_tokens[1],",",-1); 00577 00578 for (i = 0; pin_tokens[i] != NULL; i++) { 00579 net_numbers = g_list_append(net_numbers, g_strdup(pin_tokens[i])); 00580 message = g_strdup_printf ("Found pin number %s in net attribute\n", 00581 pin_tokens[i]); 00582 s_current->info_messages = g_list_append(s_current->info_messages, 00583 message); 00584 s_current->numnetpins++; 00585 } 00586 g_free(net); 00587 g_strfreev(net_tokens); 00588 g_strfreev(pin_tokens); 00589 } 00590 00591 /* check for duplicate net pin numbers */ 00592 net_numbers = g_list_sort(net_numbers, (GCompareFunc)strcmp); 00593 00594 for (cur = net_numbers; 00595 cur != NULL && g_list_next(cur) != NULL; 00596 cur = g_list_next(cur)) { 00597 if (strcmp((gchar*)cur->data, (gchar*) cur->next->data) == 0) { 00598 message = g_strdup_printf ("Found duplicate pin in net= " 00599 "attributes [%s]\n", (gchar*) cur->data); 00600 s_current->error_messages = g_list_append(s_current->error_messages, 00601 message); 00602 s_current->error_count++; 00603 } 00604 if (strcmp((gchar*) cur->data, "0") == 0) { 00605 message = g_strdup ("Found pinnumber 0 in net= attribute\n"); 00606 s_current->error_messages = g_list_append(s_current->error_messages, 00607 message); 00608 s_current->error_count++; 00609 } 00610 } 00611 00612 /* collect all pin numbers */ 00613 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 00614 OBJECT *o_current = iter->data; 00615 00616 if (o_current->type == OBJ_PIN) { 00617 s_current->numpins++; 00618 00619 missing_pinnumber_attrib_sum = 0; 00620 multiple_pinnumber_attrib_sum = 0; 00621 00622 for (counter = 0; 00623 (string = o_attrib_search_object_attribs_by_name (o_current, "pinnumber", 00624 counter)) != NULL; 00625 counter++) { 00626 00627 message = g_strdup_printf ("Found pinnumber=%s attribute\n", string); 00628 s_current->info_messages = g_list_append(s_current->info_messages, 00629 message); 00630 00631 if (counter == 0) { /* collect the first appearance */ 00632 pin_numbers = g_list_append(pin_numbers, string); 00633 } 00634 if (counter >= 1) { 00635 message = g_strdup_printf ("Found multiple pinnumber=%s attributes" 00636 " on one pin\n", string); 00637 s_current->error_messages = g_list_append(s_current->error_messages, 00638 message); 00639 multiple_pinnumber_attrib_sum++; 00640 s_current->error_count++; 00641 g_free(string); 00642 } 00643 } 00644 00645 if (counter == 0) { 00646 message = g_strdup ("Missing pinnumber= attribute\n"); 00647 s_current->error_messages = g_list_append(s_current->error_messages, 00648 message); 00649 missing_pinnumber_attrib_sum++; 00650 s_current->error_count++; 00651 } 00652 00653 s_current->missing_pinnumber_attrib += missing_pinnumber_attrib_sum; 00654 s_current->multiple_pinnumber_attrib += multiple_pinnumber_attrib_sum; 00655 } 00656 } 00657 00658 /* check for duplicate pinlabel numbers */ 00659 pin_numbers = g_list_sort(pin_numbers, (GCompareFunc)strcmp); 00660 for (cur = pin_numbers; 00661 cur != NULL && g_list_next(cur) != NULL; 00662 cur = g_list_next(cur)) { 00663 if (strcmp((gchar*)cur->data, (gchar*) cur->next->data) == 0) { 00664 message = g_strdup_printf ("Found duplicate pinnumber=%s attribute " 00665 "in the symbol\n", (gchar*) cur->data); 00666 s_current->error_messages = g_list_append(s_current->error_messages, 00667 message); 00668 s_current->error_count++; 00669 s_current->duplicate_pinnumber_attrib++; 00670 } 00671 if (strcmp((gchar*) cur->data, "0") == 0) { 00672 message = g_strdup ("Found pinnumber=0 attribute\n"); 00673 s_current->error_messages = g_list_append(s_current->error_messages, 00674 message); 00675 s_current->error_count++; 00676 } 00677 } 00678 00679 /* Check for all pins that are in both lists and print a warning. 00680 Sometimes this is useful and sometimes it's an error. */ 00681 00682 cur = net_numbers; 00683 cur2 = pin_numbers; 00684 00685 while (cur != NULL && cur2 != NULL) { 00686 00687 i = strcmp((gchar*)cur->data, (gchar*)cur2->data); 00688 00689 if (i == 0) { 00690 message = g_strdup_printf ("Found the same number in a pinnumber " 00691 "attribute and in a net attribute [%s]\n", 00692 (gchar*) cur->data); 00693 s_current->warning_messages = g_list_append(s_current->warning_messages, 00694 message); 00695 s_current->warning_count++; 00696 cur = g_list_next(cur); 00697 00698 } else if ( i > 0 ) { 00699 cur2 = g_list_next(cur2); 00700 00701 } else { /* i < 0 */ 00702 cur = g_list_next(cur); 00703 } 00704 } 00705 00706 /* FIXME: this is not correct if a pinnumber is defined as pinnumber and 00707 inside a net. We have to calculate the union set */ 00708 message = g_strdup_printf ("Found %d pins inside symbol\n", 00709 s_current->numpins + s_current->numnetpins); 00710 s_current->info_messages = g_list_append(s_current->info_messages, 00711 message); 00712 00713 g_list_foreach(pin_numbers, (GFunc) g_free, NULL); 00714 g_list_free(pin_numbers); 00715 g_list_foreach(net_numbers, (GFunc) g_free, NULL); 00716 g_list_free(net_numbers); 00717 } 00718 00719 void 00720 s_check_pin_ongrid (const GList *obj_list, SYMCHECK *s_current) 00721 { 00722 int x1, x2, y1, y2; 00723 const GList *iter; 00724 char *message; 00725 00726 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 00727 OBJECT *o_current = iter->data; 00728 00729 if (o_current->type == OBJ_PIN) { 00730 x1 = o_current->line->x[0]; 00731 y1 = o_current->line->y[0]; 00732 x2 = o_current->line->x[1]; 00733 y2 = o_current->line->y[1]; 00734 00735 if (x1 % 100 != 0 || y1 % 100 != 0) { 00736 message = g_strdup_printf("Found offgrid pin at location" 00737 " (x1=%d,y1=%d)\n", x1, y1); 00738 /* error if it is the whichend, warning if not */ 00739 if (o_current->whichend == 0) { 00740 s_current->error_messages = g_list_append(s_current->error_messages, 00741 message); 00742 s_current->error_count++; 00743 } 00744 else { 00745 s_current->warning_messages = g_list_append(s_current->warning_messages, 00746 message); 00747 s_current->warning_count++; 00748 } 00749 } 00750 if (x2 % 100 != 0 || y2 % 100 != 0) { 00751 message = g_strdup_printf("Found offgrid pin at location" 00752 " (x2=%d,y2=%d)\n", x2, y2); 00753 /* error when whichend, warning if not */ 00754 if (o_current-> whichend != 0) { 00755 s_current->error_messages = g_list_append(s_current->error_messages, 00756 message); 00757 s_current->error_count++; 00758 } 00759 else { 00760 s_current->warning_messages = g_list_append(s_current->warning_messages, 00761 message); 00762 s_current->warning_count++; 00763 } 00764 } 00765 } 00766 } 00767 } 00768 00769 00770 void 00771 s_check_slotdef (const GList *obj_list, SYMCHECK *s_current) 00772 { 00773 char* value = NULL; 00774 char* slotdef = NULL; 00775 char* slotnum = NULL; 00776 char* pins = NULL; 00777 char* temp = NULL; 00778 char numslots_str[10]; 00779 int slot; 00780 int i,j; 00781 char *message; 00782 char tempstr1[10]; 00783 /* pinlist will store the pin definitions for each slot */ 00784 /* example: pinlist[0] = 3,2,8,4,1 ; pinlist[1] = 5,6,8,4,7 */ 00785 char** pinlist = NULL; 00786 int n,m; 00787 char* pin; 00788 char* cmp; 00789 int match; 00790 gboolean error_parsing = FALSE; 00791 int errors_found = 0; 00792 00793 /* look for numslots to see if this symbol has slotting info */ 00794 value = o_attrib_search_floating_attribs_by_name (obj_list, "numslots", 0); 00795 00796 if (!value) { 00797 message = g_strdup ("Did not find numslots= attribute, not checking slotting\n"); 00798 s_current->warning_messages = g_list_append(s_current->warning_messages, 00799 message); 00800 s_current->warning_count++; 00801 message = g_strdup ("If this symbol does not need slotting, set numslots to zero (numslots=0)\n"); 00802 s_current->info_messages = g_list_append(s_current->info_messages, 00803 message); 00804 return; 00805 } 00806 00807 s_current->numslots=atoi(value); 00808 sprintf(numslots_str, "%d", s_current->numslots); 00809 g_free(value); 00810 00811 message = g_strdup_printf ("Found numslots=%s attribute\n", numslots_str); 00812 s_current->info_messages = g_list_append(s_current->info_messages, 00813 message); 00814 00815 if (s_current->numslots == 0) { 00816 message = g_strdup ("numslots set to zero, symbol does not have slots\n"); 00817 s_current->info_messages = g_list_append(s_current->info_messages, 00818 message); 00819 return; 00820 } 00821 00822 00823 pinlist = (char**)g_malloc0(sizeof(*pinlist) * s_current->numslots); 00824 00825 i = 0; 00826 /* get the slotdef attribute */ 00827 slotdef = o_attrib_search_floating_attribs_by_name (obj_list, "slotdef", 0); 00828 while ((slotdef != NULL) && (!error_parsing)) 00829 { 00830 00831 if (i > s_current->numslots-1) { 00832 00833 sprintf(tempstr1, "%d", i+1); /* i starts at zero */ 00834 message = g_strdup_printf ( 00835 "Found %s slotdef= attributes. Expecting %s slotdef= attributes\n", 00836 tempstr1, numslots_str); 00837 s_current->error_messages = g_list_append(s_current->error_messages, 00838 message); 00839 00840 s_current->error_count++; 00841 s_current->slotting_errors++; 00842 } 00843 00844 message = g_strdup_printf ("Found slotdef=%s attribute\n", slotdef); 00845 s_current->info_messages = g_list_append(s_current->info_messages, 00846 message); 00847 00848 slotnum = u_basic_breakup_string(slotdef, ':', 0); 00849 if (!slotnum) 00850 { 00851 message = g_strdup_printf ( 00852 "Invalid slotdef=%s attributes, not continuing\n", 00853 slotdef); 00854 s_current->error_messages = g_list_append(s_current->error_messages, 00855 message); 00856 s_current->error_count++; 00857 s_current->slotting_errors++; 00858 error_parsing = TRUE; 00859 continue; 00860 } 00861 00862 if (strcmp(slotnum, "0") == 0) { 00863 message = g_strdup_printf ( 00864 "Found a zero slot in slotdef=%s\n", 00865 slotdef); 00866 s_current->error_messages = g_list_append(s_current->error_messages, 00867 message); 00868 s_current->error_count++; 00869 } 00870 00871 slot = atoi(slotnum); 00872 g_free(slotnum); 00873 00874 /* make sure that the slot # is less than the number of slots */ 00875 if (slot > s_current->numslots) { 00876 sprintf(tempstr1, "%d", slot); 00877 message = g_strdup_printf ( 00878 "Slot %s is larger then the maximum number (%s) of slots\n", 00879 tempstr1, numslots_str); 00880 s_current->error_messages = g_list_append(s_current->error_messages, 00881 message); 00882 00883 s_current->error_count++; 00884 s_current->slotting_errors++; 00885 } 00886 00887 /* skip over the : */ 00888 pins = strchr(slotdef, ':'); 00889 if (!pins) { 00890 message = g_strdup_printf ( 00891 "Invalid slotdef=%s attributes, not continuing\n", 00892 slotdef); 00893 s_current->error_messages = g_list_append(s_current->error_messages, 00894 message); 00895 s_current->error_count++; 00896 s_current->slotting_errors++; 00897 error_parsing = TRUE; 00898 continue; 00899 } 00900 pins++; /* get past that : */ 00901 if (!pins) { 00902 message = g_strdup_printf ( 00903 "Invalid slotdef=%s attributes, not continuing\n", 00904 slotdef); 00905 s_current->error_messages = g_list_append(s_current->error_messages, 00906 message); 00907 s_current->error_count++; 00908 s_current->slotting_errors++; 00909 error_parsing = TRUE; 00910 continue; 00911 } 00912 00913 if (*pins == '\0') { 00914 message = g_strdup_printf ( 00915 "Invalid slotdef=%s attributes, not continuing\n", 00916 slotdef); 00917 s_current->error_messages = g_list_append(s_current->error_messages, 00918 message); 00919 s_current->error_count++; 00920 s_current->slotting_errors++; 00921 error_parsing = TRUE; 00922 continue; 00923 } 00924 00925 if ((slot > 0) && (slot <= s_current->numslots)) { 00926 if (pinlist[slot-1]) { 00927 message = g_strdup_printf ("Duplicate slot number in slotdef=%s\n", 00928 slotdef); 00929 s_current->error_messages = g_list_append(s_current->error_messages, 00930 message); 00931 s_current->error_count++; 00932 s_current->slotting_errors++; 00933 } else { 00934 pinlist[slot-1] = g_strdup_printf(",%s,", pins); 00935 } 00936 } 00937 00938 j = 0; 00939 do { 00940 if (temp) { 00941 g_free(temp); 00942 temp = NULL; 00943 } 00944 00945 temp = u_basic_breakup_string(pins, ',', j); 00946 00947 if (!temp && j < s_current->numpins) { 00948 message = g_strdup_printf ( 00949 "Not enough pins in slotdef=%s\n", 00950 slotdef); 00951 s_current->error_messages = g_list_append(s_current->error_messages, 00952 message); 00953 s_current->error_count++; 00954 s_current->slotting_errors++; 00955 break; 00956 } 00957 00958 if (j > s_current->numpins) { 00959 message = g_strdup_printf ( 00960 "Too many pins in slotdef=%s\n", 00961 slotdef); 00962 s_current->error_messages = g_list_append(s_current->error_messages, 00963 message); 00964 s_current->error_count++; 00965 s_current->slotting_errors++; 00966 g_free(temp); 00967 temp = NULL; 00968 break; 00969 } 00970 00971 if (temp && strcmp(temp, "0") == 0) { 00972 message = g_strdup_printf ( 00973 "Found a zero pin in slotdef=%s\n", 00974 slotdef); 00975 s_current->error_messages = g_list_append(s_current->error_messages, 00976 message); 00977 s_current->error_count++; 00978 } 00979 00980 j++; 00981 } while (temp); 00982 00983 g_free(temp); 00984 00985 g_free(slotdef); 00986 slotdef = NULL; 00987 00988 i++; 00989 slotdef = o_attrib_search_floating_attribs_by_name (obj_list, "slotdef", i); 00990 } 00991 00992 if (!slotdef && i < s_current->numslots) { 00993 message = g_strdup_printf ( 00994 "Missing slotdef= (there should be %s slotdef= attributes)\n", 00995 numslots_str); 00996 s_current->error_messages = g_list_append(s_current->error_messages, 00997 message); 00998 s_current->error_count++; 00999 s_current->slotting_errors++; 01000 } else { 01001 01002 /* Validate that pinslist does not contain a null entry. If any entry */ 01003 /* is null, that means the slotdef= attribute was malformed to start */ 01004 /* with. */ 01005 for (i = 0; i < s_current->numslots; i++) { 01006 if (pinlist[i] == NULL) { 01007 errors_found++; 01008 } 01009 } 01010 01011 if (errors_found) { 01012 message = g_strdup_printf( 01013 "Malformed slotdef= (the format is #:#,#,#,...)\n"); 01014 s_current->error_messages = g_list_append(s_current->error_messages, 01015 message); 01016 s_current->error_count++; 01017 s_current->slotting_errors++; 01018 } else { 01019 /* Now compare each pin with the rest */ 01020 s_current->numslotpins = 0; 01021 for (i = 0; i < s_current->numslots; i++) { 01022 for (n = 1; n <= s_current->numpins; n++) { 01023 /* Get the number of one pin */ 01024 pin = u_basic_breakup_string(pinlist[i], ',', n); 01025 if (pin && *pin) { 01026 match = FALSE; 01027 for (j = i - 1; j >= 0 && !match; j--) { 01028 for (m = 1; m <= s_current->numpins && !match; m++) { 01029 /* Get the number of the other pin */ 01030 cmp = u_basic_breakup_string(pinlist[j], ',', m); 01031 if (cmp && *cmp) { 01032 match = (0 == strcmp (pin, cmp)); 01033 g_free(cmp); 01034 } 01035 } 01036 } 01037 if (!match) { 01038 /* If they don't match, then increase the number of pins */ 01039 s_current->numslotpins++; 01040 } 01041 g_free(pin); 01042 } 01043 } 01044 } 01045 message = g_strdup_printf ("Found %d distinct pins in slots\n", 01046 s_current->numslotpins); 01047 s_current->info_messages = g_list_append(s_current->info_messages, 01048 message); 01049 } 01050 } 01051 01052 g_free(slotdef); 01053 if (pinlist) { 01054 /* Free the pinlist */ 01055 for (i = 0; i < s_current->numslots; i++) { 01056 g_free(pinlist[i]); 01057 } 01058 g_free(pinlist); 01059 } 01060 01061 return; 01062 } 01063 01064 01065 void 01066 s_check_oldpin (const GList *obj_list, SYMCHECK *s_current) 01067 { 01068 const GList *iter; 01069 char *ptr; 01070 int found_old = FALSE; 01071 int number_counter = 0; 01072 char *message; 01073 01074 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01075 OBJECT *o_current = iter->data; 01076 01077 if (o_current->type == OBJ_TEXT) 01078 { 01079 if (strstr(o_current->text->string, "pin")) 01080 { 01081 /* skip over "pin" */ 01082 ptr = o_current->text->string + 3; 01083 01084 found_old = FALSE; 01085 number_counter = 0; 01086 while (ptr && *ptr > '0' && *ptr < '9') 01087 { 01088 number_counter++; 01089 ptr++; 01090 } 01091 01092 if (ptr && *ptr == '=') 01093 { 01094 found_old++; 01095 } 01096 01097 if (!ptr) 01098 continue; 01099 01100 /* found no numbers inbetween pin and = */ 01101 if (number_counter == 0) 01102 continue; 01103 01104 /* skip over = char */ 01105 ptr++; 01106 01107 while (ptr && *ptr > '0' && *ptr < '9') 01108 { 01109 ptr++; 01110 } 01111 01112 if (*ptr == '\0') 01113 { 01114 found_old++; 01115 } 01116 01117 /* 2 matches -> number found after pin and only numbers after = sign */ 01118 if (found_old == 2) 01119 { 01120 message = g_strdup_printf ( 01121 "Found old pin#=# attribute: %s\n", 01122 o_current->text->string); 01123 s_current->error_messages = g_list_append(s_current->error_messages, 01124 message); 01125 01126 s_current->found_oldpin_attrib += found_old; 01127 s_current->error_count++; 01128 01129 } 01130 } 01131 } 01132 } 01133 01134 } 01135 01136 01137 void 01138 s_check_oldslot (const GList *obj_list, SYMCHECK *s_current) 01139 { 01140 const GList *iter; 01141 char *ptr; 01142 int found_old = FALSE; 01143 int number_counter = 0; 01144 char *message; 01145 01146 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01147 OBJECT *o_current = iter->data; 01148 01149 if (o_current->type == OBJ_TEXT) 01150 { 01151 if (strstr(o_current->text->string, "slot")) 01152 { 01153 /* skip over "slot" */ 01154 ptr = o_current->text->string + 4; 01155 01156 found_old = FALSE; 01157 number_counter = 0; 01158 while (ptr && *ptr > '0' && *ptr < '9') 01159 { 01160 number_counter++; 01161 ptr++; 01162 } 01163 01164 if (ptr && *ptr == '=') 01165 { 01166 found_old++; 01167 } 01168 01169 if (!ptr) 01170 continue; 01171 01172 /* found no numbers inbetween pin and = */ 01173 if (number_counter == 0) 01174 continue; 01175 01176 /* skip over = char */ 01177 ptr++; 01178 01179 while ((ptr && (*ptr > '0') && (*ptr < '9')) || (*ptr == ',')) 01180 { 01181 ptr++; 01182 } 01183 01184 if (*ptr == '\0') 01185 { 01186 found_old++; 01187 } 01188 01189 /* 2 matches -> number found after slot and only numbers after = */ 01190 if (found_old == 2) 01191 { 01192 message = g_strdup_printf ( 01193 "Found old slot#=# attribute: %s\n", 01194 o_current->text->string); 01195 s_current->error_messages = g_list_append(s_current->error_messages, 01196 message); 01197 s_current->found_oldslot_attrib += found_old; 01198 s_current->error_count++; 01199 01200 } 01201 } 01202 } 01203 } 01204 } 01205 01206 01207 void 01208 s_check_nets_buses (const GList *obj_list, SYMCHECK *s_current) 01209 { 01210 const GList *iter; 01211 char *message; 01212 01213 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01214 OBJECT *o_current = iter->data; 01215 01216 if (o_current->type == OBJ_NET) 01217 { 01218 message = 01219 g_strdup ("Found a net inside a symbol\n"); 01220 s_current->error_messages = g_list_append(s_current->error_messages, 01221 message); 01222 s_current->found_net++; 01223 s_current->error_count++; 01224 } 01225 01226 if (o_current->type == OBJ_BUS) 01227 { 01228 message = 01229 g_strdup ("Found a bus inside a symbol\n"); 01230 s_current->error_messages = g_list_append(s_current->error_messages, 01231 message); 01232 s_current->found_bus++; 01233 s_current->error_count++; 01234 } 01235 01236 } 01237 } 01238 01239 void 01240 s_check_connections (const GList *obj_list, SYMCHECK *s_current) 01241 { 01242 const GList *iter; 01243 char *message; 01244 01245 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01246 OBJECT *o_current = iter->data; 01247 01248 if (o_current->conn_list) { 01249 message = 01250 g_strdup ("Found a connection inside a symbol\n"); 01251 s_current->error_messages = g_list_append(s_current->error_messages, 01252 message); 01253 s_current->found_connection++; 01254 s_current->error_count++; 01255 } 01256 } 01257 } 01258 01259 void 01260 s_check_missing_attribute(OBJECT *object, char *attribute, SYMCHECK *s_current) 01261 { 01262 char *string; 01263 int found_first=FALSE; 01264 int counter=0; 01265 char *message; 01266 01267 if (!attribute) { 01268 return; 01269 } 01270 01271 string = o_attrib_search_object_attribs_by_name (object, attribute, counter); 01272 if (!string) 01273 { 01274 message = g_strdup_printf ( 01275 "Missing %s= attribute\n", 01276 attribute); 01277 s_current->warning_messages = g_list_append(s_current->warning_messages, 01278 message); 01279 s_current->warning_count++; 01280 } 01281 01282 while (string) 01283 { 01284 01285 if (found_first) { 01286 message = g_strdup_printf ( 01287 "Found multiple %s=%s attributes on one pin\n", 01288 attribute, string); 01289 s_current->error_messages = g_list_append(s_current->error_messages, 01290 message); 01291 s_current->error_count++; 01292 } 01293 01294 /* this is the first attribute found */ 01295 if (!found_first) { 01296 01297 message = g_strdup_printf ( 01298 "Found %s=%s attribute\n", 01299 attribute, string); 01300 s_current->info_messages = g_list_append(s_current->info_messages, 01301 message); 01302 found_first=TRUE; 01303 } 01304 01305 g_free(string); 01306 01307 counter++; 01308 string = o_attrib_search_object_attribs_by_name (object, attribute, counter); 01309 } 01310 01311 } 01312 01313 void 01314 s_check_missing_attributes (const GList *obj_list, SYMCHECK *s_current) 01315 { 01316 const GList *iter; 01317 char *message; 01318 01319 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01320 OBJECT *o_current = iter->data; 01321 01322 if (o_current->type == OBJ_PIN) 01323 { 01324 s_check_missing_attribute(o_current, "pinlabel", s_current); 01325 s_check_missing_attribute(o_current, "pintype", s_current); 01326 } 01327 01328 if (o_current->type == OBJ_TEXT) 01329 { 01330 if (strstr(o_current->text->string, "footprint=")) { 01331 message = g_strdup_printf ( 01332 "Found %s attribute\n", 01333 o_current->text->string); 01334 s_current->info_messages = g_list_append(s_current->info_messages, 01335 message); 01336 s_current->found_footprint++; 01337 } 01338 01339 if (strstr(o_current->text->string, "refdes=")) { 01340 message = g_strdup_printf ( 01341 "Found %s attribute\n", 01342 o_current->text->string); 01343 s_current->info_messages = g_list_append(s_current->info_messages, 01344 message); 01345 s_current->found_refdes++; 01346 } 01347 01348 } 01349 } 01350 01351 if (s_current->found_footprint == 0) { 01352 message = g_strdup ("Missing footprint= attribute\n"); 01353 s_current->warning_messages = g_list_append(s_current->warning_messages, 01354 message); 01355 s_current->warning_count++; 01356 } 01357 01358 if (s_current->found_footprint > 1) { 01359 message = g_strdup ("Multiple footprint= attributes found\n"); 01360 s_current->error_messages = g_list_append(s_current->error_messages, 01361 message); 01362 s_current->error_count++; 01363 01364 } 01365 01366 if (s_current->found_refdes == 0) { 01367 message = g_strdup ("Missing refdes= attribute\n"); 01368 s_current->warning_messages = g_list_append(s_current->warning_messages, 01369 message); 01370 s_current->warning_count++; 01371 01372 } 01373 01374 if (s_current->found_refdes > 1) { 01375 message = g_strdup ("Multiple refdes= attributes found\n"); 01376 s_current->error_messages = g_list_append(s_current->error_messages, 01377 message); 01378 s_current->error_count++; 01379 } 01380 01381 } 01382 01383 void s_check_pintype (const GList *obj_list, SYMCHECK *s_current) 01384 { 01385 const GList *iter; 01386 int counter=0; 01387 char *pintype; 01388 char *message; 01389 char *pintypes[] = {"in", "out", "io", "oc", "oe", 01390 "pas", "tp", "tri", "clk", "pwr", 01391 NULL}; 01392 01393 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 01394 OBJECT *o_current = iter->data; 01395 01396 if (o_current->type == OBJ_PIN) { 01397 01398 for (counter = 0; 01399 (pintype = o_attrib_search_object_attribs_by_name (o_current, "pintype", 01400 counter)) != NULL; 01401 counter++) { 01402 01403 message = g_strdup_printf("Found pintype=%s attribute\n", pintype); 01404 s_current->info_messages = g_list_append(s_current->info_messages, 01405 message); 01406 01407 if ( ! s_check_list_has_item(pintypes, pintype)) { 01408 message = g_strdup_printf ("Invalid pintype=%s attribute\n", pintype); 01409 s_current->error_messages = g_list_append(s_current->error_messages, 01410 message); 01411 s_current->error_count++; 01412 } 01413 01414 g_free(pintype); 01415 } 01416 } 01417 } 01418 }