static BomList * bom_insert (char *refdes, char *descr, char *value, BomList * bom) { BomList *newlist, *cur, *prev = NULL; if (bom == NULL) { /* this is the first element so automatically create an entry */ if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } newlist->next = NULL; newlist->descr = strdup (descr); newlist->value = strdup (value); newlist->num = 1; newlist->refdes = string_insert (refdes, NULL); return (newlist); } /* search and see if we already have used one of these components */ cur = bom; while (cur != NULL) { if ((NSTRCMP (descr, cur->descr) == 0) && (NSTRCMP (value, cur->value) == 0)) { cur->num++; cur->refdes = string_insert (refdes, cur->refdes); break; } prev = cur; cur = cur->next; } if (cur == NULL) { if ((newlist = (BomList *) malloc (sizeof (BomList))) == NULL) { fprintf (stderr, "malloc() failed in bom_insert()\n"); exit (1); } prev->next = newlist; newlist->next = NULL; newlist->descr = strdup (descr); newlist->value = strdup (value); newlist->num = 1; newlist->refdes = string_insert (refdes, NULL); } return (bom); }
/*! * \brief Find a particular pad from an element name and pin number. */ static bool FindPad (char *ElementName, char *PinNum, ConnectionType * conn, bool Same) { ElementType *element; GList *i; if ((element = SearchElementByName (PCB->Data, ElementName)) == NULL) return false; for (i = element->Pad; i != NULL; i = g_list_next (i)) { PadType *pad = i->data; if (NSTRCMP (PinNum, pad->Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, pad))) { conn->type = PAD_TYPE; conn->ptr1 = element; conn->ptr2 = pad; conn->group = TEST_FLAG (ONSOLDERFLAG, pad) ? bottom_group : top_group; if (TEST_FLAG (EDGE2FLAG, pad)) { conn->X = pad->Point2.X; conn->Y = pad->Point2.Y; } else { conn->X = pad->Point1.X; conn->Y = pad->Point1.Y; } return true; } } for (i = element->Pin; i != NULL; i = g_list_next (i)) { PinType *pin = i->data; if (!TEST_FLAG (HOLEFLAG, pin) && pin->Number && NSTRCMP (PinNum, pin->Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, pin))) { conn->type = PIN_TYPE; conn->ptr1 = element; conn->ptr2 = pin; conn->group = bottom_group; /* any layer will do */ conn->X = pin->X; conn->Y = pin->Y; return true; } } return false; }
/* --------------------------------------------------------------------------- * Find a particular pad from an element name and pin number */ static bool FindPad (char *ElementName, char *PinNum, ConnectionType * conn, bool Same) { ElementTypePtr element; Cardinal i; if ((element = SearchElementByName (PCB->Data, ElementName)) != NULL) { for (i = 0; i < element->PadN; i++) if (NSTRCMP (PinNum, element->Pad[i].Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, &element-> Pad[i]))) { conn->type = PAD_TYPE; conn->ptr2 = &element->Pad[i]; conn->group = TEST_FLAG (ONSOLDERFLAG, &element->Pad[i]) ? SLayer : CLayer; if (TEST_FLAG (EDGE2FLAG, &element->Pad[i])) { conn->X = element->Pad[i].Point2.X; conn->Y = element->Pad[i].Point2.Y; } else { conn->X = element->Pad[i].Point1.X; conn->Y = element->Pad[i].Point1.Y; } break; } if (i == element->PadN) { for (i = 0; i < element->PinN; i++) if (!TEST_FLAG (HOLEFLAG, &element->Pin[i]) && element->Pin[i].Number && NSTRCMP (PinNum, element->Pin[i].Number) == 0 && (!Same || !TEST_FLAG (DRCFLAG, &element->Pin[i]))) { conn->type = PIN_TYPE; conn->ptr2 = &element->Pin[i]; conn->group = SLayer; /* any layer will do */ conn->X = element->Pin[i].X; conn->Y = element->Pin[i].Y; break; } if (i == element->PinN) return (false); } conn->ptr1 = element; return (true); } return (false); }
Resource * resource_subres(const Resource *res, const char *name) { int i; if (res == 0 || name == 0) return 0; for (i=0; i<res->c; i++) if (res->v[i].name && res->v[i].subres && NSTRCMP(res->v[i].name, name) == 0) return res->v[i].subres; return 0; }
char * resource_value(const Resource *res, char *name) { int i; if (res == 0 || name == 0) return 0; for (i=0; i<res->c; i++) if (res->v[i].name && res->v[i].value && NSTRCMP(res->v[i].name, name) == 0) return res->v[i].value; return 0; }
void SetRouteStyle (char *name) { char num[10]; STYLE_LOOP (PCB); { if (name && NSTRCMP (name, style->Name) == 0) { sprintf (num, "%d", n + 1); hid_actionl ("RouteStyle", num, NULL); break; } } END_LOOP; }
/* --------------------------------------------------------------------------- * Add a new net to the netlist menu */ LibraryMenuTypePtr CreateNewNet (LibraryTypePtr lib, char *name, char *style) { LibraryMenuTypePtr menu; char temp[64]; sprintf (temp, " %s", name); menu = GetLibraryMenuMemory (lib); menu->Name = strdup (temp); menu->flag = 1; /* net is enabled by default */ if (style == NULL || NSTRCMP ("(unknown)", style) == 0) menu->Style = NULL; else menu->Style = strdup (style); return (menu); }
/* --------------------------------------------------------------------------- * searches for an element by its board name. * The function returns a pointer to the element, NULL if not found */ ElementTypePtr SearchElementByName (DataTypePtr Base, char *Name) { ElementTypePtr result = NULL; ELEMENT_LOOP (Base); { if (element->Name[1].TextString && NSTRCMP (element->Name[1].TextString, Name) == 0) { result = element; return (result); } } END_LOOP; return result; }
/*! * \brief Read the library-netlist build a true Netlist structure. */ NetListType * ProcNetlist (LibraryType *net_menu) { ConnectionType *connection; ConnectionType LastPoint; NetType *net; static NetListType *Wantlist = NULL; if (!net_menu->MenuN) return (NULL); FreeNetListMemory (Wantlist); free (Wantlist); badnet = false; /* find layer groups of the component side and solder side */ bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE); top_group = GetLayerGroupNumberBySide (TOP_SIDE); Wantlist = (NetListType *)calloc (1, sizeof (NetListType)); if (Wantlist) { ALLPIN_LOOP (PCB->Data); { pin->Spare = NULL; CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { pad->Spare = NULL; CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; MENU_LOOP (net_menu); { if (menu->Name[0] == '*' || menu->flag == 0) { badnet = true; continue; } net = GetNetMemory (Wantlist); if (menu->Style) { STYLE_LOOP (PCB); { if (style->Name && !NSTRCMP (style->Name, menu->Style)) { net->Style = style; break; } } END_LOOP; } else /* default to NULL if none found */ net->Style = NULL; ENTRY_LOOP (menu); { if (SeekPad (entry, &LastPoint, false)) { if (TEST_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2)) Message (_ ("Error! Element %s pin %s appears multiple times in the netlist file.\n"), NAMEONPCB_NAME ((ElementType *) LastPoint.ptr1), (LastPoint.type == PIN_TYPE) ? ((PinType *) LastPoint.ptr2)-> Number : ((PadType *) LastPoint.ptr2)->Number); else { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } else badnet = true; /* check for more pins with the same number */ for (; SeekPad (entry, &LastPoint, true);) { connection = GetConnectionMemory (net); *connection = LastPoint; /* indicate expect net */ connection->menu = menu; /* mark as visited */ SET_FLAG (DRCFLAG, (PinType *) LastPoint.ptr2); if (LastPoint.type == PIN_TYPE) ((PinType *) LastPoint.ptr2)->Spare = (void *) menu; else ((PadType *) LastPoint.ptr2)->Spare = (void *) menu; } } END_LOOP; } END_LOOP; } /* clear all visit marks */ ALLPIN_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pin); } ENDALL_LOOP; ALLPAD_LOOP (PCB->Data); { CLEAR_FLAG (DRCFLAG, pad); } ENDALL_LOOP; return (Wantlist); }
/* This function loads the newlib footprints into the Library. * It examines all directories pointed to by Settings.LibraryTree. * In each directory specified there, it looks both in that directory, * as well as *one* level down. It calls the subfunction * LoadNewlibFootprintsFromDir to put the footprints into PCB's internal * datastructures. */ static int ParseLibraryTree (void) { char toppath[MAXPATHLEN + 1]; /* String holding abs path to top level library dir */ char working[MAXPATHLEN + 1]; /* String holding abs path to working dir */ char *libpaths; /* String holding list of library paths to search */ char *p; /* Helper string used in iteration */ DIR *dirobj; /* Iterable directory object */ struct dirent *direntry = NULL; /* Object holding individual directory entries */ struct stat buffer; /* buffer used in stat */ int n_footprints = 0; /* Running count of footprints found */ /* Initialize path, working by writing 0 into every byte. */ memset (toppath, 0, sizeof toppath); memset (working, 0, sizeof working); /* Save the current working directory as an absolute path. * This fcn writes the abs path into the memory pointed to by the input arg. */ if (GetWorkingDirectory (working) == NULL) { Message (_("ParseLibraryTree: Could not determine initial working directory\n")); return 0; } /* Additional loop to allow for multiple 'newlib' style library directories * called out in Settings.LibraryTree */ libpaths = strdup (Settings.LibraryTree); for (p = strtok (libpaths, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) { /* remove trailing path delimeter */ strncpy (toppath, p, sizeof (toppath) - 1); /* start out in the working directory in case the path is a * relative path */ if (chdir (working)) { ChdirErrorMessage (working); free (libpaths); return 0; } /* * Next change to the directory which is the top of the library tree * and extract its abs path. */ if (chdir (toppath)) { ChdirErrorMessage (toppath); continue; } if (GetWorkingDirectory (toppath) == NULL) { Message (_("ParseLibraryTree: Could not determine new working directory\n")); continue; } #ifdef DEBUG printf("In ParseLibraryTree, looking for newlib footprints inside top level directory %s ... \n", toppath); #endif /* Next read in any footprints in the top level dir */ n_footprints += LoadNewlibFootprintsFromDir("(local)", toppath); /* Then open this dir so we can loop over its contents. */ if ((dirobj = opendir (toppath)) == NULL) { OpendirErrorMessage (toppath); continue; } /* Now loop over files in this directory looking for subdirs. * For each direntry which is a valid subdirectory, * try to load newlib footprints inside it. */ while ((direntry = readdir (dirobj)) != NULL) { #ifdef DEBUG printf("In ParseLibraryTree loop examining 2nd level direntry %s ... \n", direntry->d_name); #endif /* Find subdirectories. Ignore entries beginning with "." and CVS * directories. */ if (!stat (direntry->d_name, &buffer) && S_ISDIR (buffer.st_mode) && direntry->d_name[0] != '.' && NSTRCMP (direntry->d_name, "CVS") != 0) { /* Found a valid subdirectory. Try to load footprints from it. */ n_footprints += LoadNewlibFootprintsFromDir(direntry->d_name, toppath); } } closedir (dirobj); } /* restore the original working directory */ if (chdir (working)) ChdirErrorMessage (working); #ifdef DEBUG printf("Leaving ParseLibraryTree, found %d footprints.\n", n_footprints); #endif free (libpaths); return n_footprints; }
/* --------------------------------------------------------------------------- * Compute cost function. * note that area overlap cost is correct for SMD devices: SMD devices on * opposite sides of the board don't overlap. * * Algorithms follow those described in sections 4.1 of * "Placement and Routing of Electronic Modules" edited by Michael Pecht * Marcel Dekker, Inc. 1993. ISBN: 0-8247-8916-4 TK7868.P7.P57 1993 */ static double ComputeCost (NetListTypePtr Nets, double T0, double T) { double W = 0; /* wire cost */ double delta1 = 0; /* wire congestion penalty function */ double delta2 = 0; /* module overlap penalty function */ double delta3 = 0; /* out of bounds penalty */ double delta4 = 0; /* alignment bonus */ double delta5 = 0; /* total area penalty */ Cardinal i, j; LocationType minx, maxx, miny, maxy; bool allpads, allsameside; Cardinal thegroup; BoxListType bounds = { 0, 0, NULL }; /* save bounding rectangles here */ BoxListType solderside = { 0, 0, NULL }; /* solder side component bounds */ BoxListType componentside = { 0, 0, NULL }; /* component side bounds */ /* make sure the NetList have the proper updated X and Y coords */ UpdateXY (Nets); /* wire length term. approximated by half-perimeter of minimum * rectangle enclosing the net. Note that we penalize vias in * all-SMD nets by making the rectangle a cube and weighting * the "layer height" of the net. */ for (i = 0; i < Nets->NetN; i++) { NetTypePtr n = &Nets->Net[i]; if (n->ConnectionN < 2) continue; /* no cost to go nowhere */ minx = maxx = n->Connection[0].X; miny = maxy = n->Connection[0].Y; thegroup = n->Connection[0].group; allpads = (n->Connection[0].type == PAD_TYPE); allsameside = true; for (j = 1; j < n->ConnectionN; j++) { ConnectionTypePtr c = &(n->Connection[j]); MAKEMIN (minx, c->X); MAKEMAX (maxx, c->X); MAKEMIN (miny, c->Y); MAKEMAX (maxy, c->Y); if (c->type != PAD_TYPE) allpads = false; if (c->group != thegroup) allsameside = false; } /* save bounding rectangle */ { BoxTypePtr box = GetBoxMemory (&bounds); box->X1 = minx; box->Y1 = miny; box->X2 = maxx; box->Y2 = maxy; } /* okay, add half-perimeter to cost! */ W += (maxx - minx) / 100 + (maxy - miny) / 100 + ((allpads && !allsameside) ? CostParameter.via_cost : 0); } /* now compute penalty function Wc which is proportional to * amount of overlap and congestion. */ /* delta1 is congestion penalty function */ delta1 = CostParameter.congestion_penalty * sqrt (fabs (ComputeIntersectionArea (&bounds))); #if 0 printf ("Wire Congestion Area: %f\n", ComputeIntersectionArea (&bounds)); #endif /* free bounding rectangles */ FreeBoxListMemory (&bounds); /* now collect module areas (bounding rect of pins/pads) */ /* two lists for solder side / component side. */ ELEMENT_LOOP (PCB->Data); { BoxListTypePtr thisside; BoxListTypePtr otherside; BoxTypePtr box; BoxTypePtr lastbox = NULL; BDimension thickness; BDimension clearance; if (TEST_FLAG (ONSOLDERFLAG, element)) { thisside = &solderside; otherside = &componentside; } else { thisside = &componentside; otherside = &solderside; } box = GetBoxMemory (thisside); /* protect against elements with no pins/pads */ if (element->PinN == 0 && element->PadN == 0) continue; /* initialize box so that it will take the dimensions of * the first pin/pad */ box->X1 = MAX_COORD; box->Y1 = MAX_COORD; box->X2 = -MAX_COORD; box->Y2 = -MAX_COORD; PIN_LOOP (element); { thickness = pin->Thickness / 2; clearance = pin->Clearance * 2; EXPANDRECTXY (box, pin->X - (thickness + clearance), pin->Y - (thickness + clearance), pin->X + (thickness + clearance), pin->Y + (thickness + clearance))} END_LOOP; PAD_LOOP (element); { thickness = pad->Thickness / 2; clearance = pad->Clearance * 2; EXPANDRECTXY (box, MIN (pad->Point1.X, pad->Point2.X) - (thickness + clearance), MIN (pad->Point1.Y, pad->Point2.Y) - (thickness + clearance), MAX (pad->Point1.X, pad->Point2.X) + (thickness + clearance), MAX (pad->Point1.Y, pad->Point2.Y) + (thickness + clearance))} END_LOOP; /* add a box for each pin to the "opposite side": * surface mount components can't sit on top of pins */ if (!CostParameter.fast) PIN_LOOP (element); { box = GetBoxMemory (otherside); thickness = pin->Thickness / 2; clearance = pin->Clearance * 2; /* we ignore clearance here */ /* (otherwise pins don't fit next to each other) */ box->X1 = pin->X - thickness; box->Y1 = pin->Y - thickness; box->X2 = pin->X + thickness; box->Y2 = pin->Y + thickness; /* speed hack! coalesce with last box if we can */ if (lastbox != NULL && ((lastbox->X1 == box->X1 && lastbox->X2 == box->X2 && MIN (abs (lastbox->Y1 - box->Y2), abs (box->Y1 - lastbox->Y2)) < clearance) || (lastbox->Y1 == box->Y1 && lastbox->Y2 == box->Y2 && MIN (abs (lastbox->X1 - box->X2), abs (box->X1 - lastbox->X2)) < clearance))) { EXPANDRECT (lastbox, box); otherside->BoxN--; } else lastbox = box; } END_LOOP; /* assess out of bounds penalty */ if (element->VBox.X1 < 0 || element->VBox.Y1 < 0 || element->VBox.X2 > PCB->MaxWidth || element->VBox.Y2 > PCB->MaxHeight) delta3 += CostParameter.out_of_bounds_penalty; } END_LOOP; /* compute intersection area of module areas box list */ delta2 = sqrt (fabs (ComputeIntersectionArea (&solderside) + ComputeIntersectionArea (&componentside))) * (CostParameter.overlap_penalty_min + (1 - (T / T0)) * CostParameter.overlap_penalty_max); #if 0 printf ("Module Overlap Area (solder): %f\n", ComputeIntersectionArea (&solderside)); printf ("Module Overlap Area (component): %f\n", ComputeIntersectionArea (&componentside)); #endif FreeBoxListMemory (&solderside); FreeBoxListMemory (&componentside); /* reward pin/pad x/y alignment */ /* score higher if pins/pads belong to same *type* of component */ /* XXX: subkey should be *distance* from thing aligned with, so that * aligning to something far away isn't profitable */ { /* create r tree */ PointerListType seboxes = { 0, 0, NULL } , ceboxes = { 0, 0, NULL}; struct ebox { BoxType box; ElementTypePtr element; }; direction_t dir[4] = { NORTH, EAST, SOUTH, WEST }; struct ebox **boxpp, *boxp; rtree_t *rt_s, *rt_c; int factor; ELEMENT_LOOP (PCB->Data); { boxpp = (struct ebox **) GetPointerMemory (TEST_FLAG (ONSOLDERFLAG, element) ? &seboxes : &ceboxes); *boxpp = malloc (sizeof (**boxpp)); if (*boxpp == NULL ) { fprintf (stderr, "malloc() failed in %s\n", __FUNCTION__); exit (1); } (*boxpp)->box = element->VBox; (*boxpp)->element = element; } END_LOOP; rt_s = r_create_tree ((const BoxType **) seboxes.Ptr, seboxes.PtrN, 1); rt_c = r_create_tree ((const BoxType **) ceboxes.Ptr, ceboxes.PtrN, 1); FreePointerListMemory (&seboxes); FreePointerListMemory (&ceboxes); /* now, for each element, find its neighbor on all four sides */ delta4 = 0; for (i = 0; i < 4; i++) ELEMENT_LOOP (PCB->Data); { boxp = (struct ebox *) r_find_neighbor (TEST_FLAG (ONSOLDERFLAG, element) ? rt_s : rt_c, &element->VBox, dir[i]); /* score bounding box alignments */ if (!boxp) continue; factor = 1; if (element->Name[0].TextString && boxp->element->Name[0].TextString && 0 == NSTRCMP (element->Name[0].TextString, boxp->element->Name[0].TextString)) { delta4 += CostParameter.matching_neighbor_bonus; factor++; } if (element->Name[0].Direction == boxp->element->Name[0].Direction) delta4 += factor * CostParameter.oriented_neighbor_bonus; if (element->VBox.X1 == boxp->element->VBox.X1 || element->VBox.X1 == boxp->element->VBox.X2 || element->VBox.X2 == boxp->element->VBox.X1 || element->VBox.X2 == boxp->element->VBox.X2 || element->VBox.Y1 == boxp->element->VBox.Y1 || element->VBox.Y1 == boxp->element->VBox.Y2 || element->VBox.Y2 == boxp->element->VBox.Y1 || element->VBox.Y2 == boxp->element->VBox.Y2) delta4 += factor * CostParameter.aligned_neighbor_bonus; } END_LOOP; /* free k-d tree memory */ r_destroy_tree (&rt_s); r_destroy_tree (&rt_c); } /* penalize total area used by this layout */ { LocationType minX = MAX_COORD, minY = MAX_COORD; LocationType maxX = -MAX_COORD, maxY = -MAX_COORD; ELEMENT_LOOP (PCB->Data); { MAKEMIN (minX, element->VBox.X1); MAKEMIN (minY, element->VBox.Y1); MAKEMAX (maxX, element->VBox.X2); MAKEMAX (maxY, element->VBox.Y2); } END_LOOP; if (minX < maxX && minY < maxY) delta5 = CostParameter.overall_area_penalty * sqrt ((double) (maxX - minX) * (maxY - minY) * 0.0001); } if (T == 5) { T = W + delta1 + delta2 + delta3 - delta4 + delta5; printf ("cost components are %.3f %.3f %.3f %.3f %.3f %.3f\n", W / T, delta1 / T, delta2 / T, delta3 / T, -delta4 / T, delta5 / T); } /* done! */ return W + (delta1 + delta2 + delta3 - delta4 + delta5); }
int ActionLoadVendorFrom (int argc, char **argv, Coord x, Coord y) { int i; char *fname = NULL; static char *default_file = NULL; char *sval; Resource *res, *drcres, *drlres; int type; bool free_fname = false; cached_drill = -1; fname = argc ? argv[0] : 0; if (!fname || !*fname) { fname = gui->fileselect (_("Load Vendor Resource File..."), _("Picks a vendor resource file to load.\n" "This file can contain drc settings for a\n" "particular vendor as well as a list of\n" "predefined drills which are allowed."), default_file, ".res", "vendor", HID_FILESELECT_READ); if (fname == NULL) AFAIL (load_vendor); free_fname = true; free (default_file); default_file = NULL; if (fname && *fname) default_file = strdup (fname); } /* Unload any vendor table we may have had */ n_vendor_drills = 0; n_refdes = 0; n_value = 0; n_descr = 0; FREE (vendor_drills); FREE (ignore_refdes); FREE (ignore_value); FREE (ignore_descr); /* load the resource file */ res = resource_parse (fname, NULL); if (res == NULL) { Message (_("Could not load vendor resource file \"%s\"\n"), fname); return 1; } /* figure out the vendor name, if specified */ vendor_name = (char *)UNKNOWN (resource_value (res, "vendor")); /* figure out the units, if specified */ sval = resource_value (res, "units"); if (sval == NULL) { sf = MIL_TO_COORD(1); } else if ((NSTRCMP (sval, "mil") == 0) || (NSTRCMP (sval, "mils") == 0)) { sf = MIL_TO_COORD(1); } else if ((NSTRCMP (sval, "inch") == 0) || (NSTRCMP (sval, "inches") == 0)) { sf = INCH_TO_COORD(1); } else if (NSTRCMP (sval, "mm") == 0) { sf = MM_TO_COORD(1); } else { Message ("\"%s\" is not a supported units. Defaulting to inch\n", sval); sf = INCH_TO_COORD(1); } /* default to ROUND_UP */ rounding_method = ROUND_UP; /* extract the drillmap resource */ drlres = resource_subres (res, "drillmap"); if (drlres == NULL) { Message (_("No drillmap resource found\n")); } else { sval = resource_value (drlres, "round"); if (sval != NULL) { if (NSTRCMP (sval, "up") == 0) { rounding_method = ROUND_UP; } else if (NSTRCMP (sval, "nearest") == 0) { rounding_method = CLOSEST; } else { Message (_ ("\"%s\" is not a valid rounding type. Defaulting to up\n"), sval); rounding_method = ROUND_UP; } } process_skips (resource_subres (drlres, "skips")); for (i = 0; i < drlres->c; i++) { type = resource_type (drlres->v[i]); switch (type) { case 10: /* just a number */ add_to_drills (drlres->v[i].value); break; default: break; } } } /* Extract the DRC resource */ drcres = resource_subres (res, "drc"); sval = resource_value (drcres, "copper_space"); if (sval != NULL) { PCB->Bloat = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper spacing to %.2f mils\n"), 0.01 * PCB->Bloat); } sval = resource_value (drcres, "copper_overlap"); if (sval != NULL) { PCB->Shrink = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper overlap to %.2f mils\n"), 0.01 * PCB->Shrink); } sval = resource_value (drcres, "copper_width"); if (sval != NULL) { PCB->minWid = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum copper spacing to %.2f mils\n"), 0.01 * PCB->minWid); } sval = resource_value (drcres, "silk_width"); if (sval != NULL) { PCB->minSlk = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum silk width to %.2f mils\n"), 0.01 * PCB->minSlk); } sval = resource_value (drcres, "min_drill"); if (sval != NULL) { PCB->minDrill = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum drill diameter to %.2f mils\n"), 0.01 * PCB->minDrill); } sval = resource_value (drcres, "min_ring"); if (sval != NULL) { PCB->minRing = floor (sf * atof (sval) + 0.5); Message (_("Set DRC minimum annular ring to %.2f mils\n"), 0.01 * PCB->minRing); } Message (_("Loaded %d vendor drills from %s\n"), n_vendor_drills, fname); Message (_("Loaded %d RefDes skips, %d Value skips, %d Descr skips\n"), n_refdes, n_value, n_descr); vendorMapEnable = true; apply_vendor_map (); if (free_fname) free (fname); return 0; }
/* This is a helper function for ParseLibrary Tree. Given a char *path, * it finds all newlib footprints in that dir and sticks them into the * library menu structure named entry. */ static int LoadNewlibFootprintsFromDir(char *libpath, char *toppath) { char olddir[MAXPATHLEN + 1]; /* The directory we start out in (cwd) */ char subdir[MAXPATHLEN + 1]; /* The directory holding footprints to load */ DIR *subdirobj; /* Interable object holding all subdir entries */ struct dirent *subdirentry; /* Individual subdir entry */ struct stat buffer; /* Buffer used in stat */ LibraryMenuType *menu = NULL; /* Pointer to PCB's library menu structure */ LibraryEntryType *entry; /* Pointer to individual menu entry */ size_t l; size_t len; int n_footprints = 0; /* Running count of footprints found in this subdir */ /* Cache old dir, then cd into subdir because stat is given relative file names. */ memset (subdir, 0, sizeof subdir); memset (olddir, 0, sizeof olddir); if (GetWorkingDirectory (olddir) == NULL) { Message (_("LoadNewlibFootprintsFromDir: Could not determine initial working directory\n")); return 0; } if (strcmp (libpath, "(local)") == 0) strcpy (subdir, "."); else strcpy (subdir, libpath); if (chdir (subdir)) { ChdirErrorMessage (subdir); return 0; } /* Determine subdir is abs path */ if (GetWorkingDirectory (subdir) == NULL) { Message (_("LoadNewlibFootprintsFromDir: Could not determine new working directory\n")); if (chdir (olddir)) ChdirErrorMessage (olddir); return 0; } /* First try opening the directory specified by path */ if ( (subdirobj = opendir (subdir)) == NULL ) { OpendirErrorMessage (subdir); if (chdir (olddir)) ChdirErrorMessage (olddir); return 0; } /* Get pointer to memory holding menu */ menu = GetLibraryMenuMemory (&Library); /* Populate menuname and path vars */ menu->Name = strdup (pcb_basename(subdir)); menu->directory = strdup (pcb_basename(toppath)); /* Now loop over files in this directory looking for files. * We ignore certain files which are not footprints. */ while ((subdirentry = readdir (subdirobj)) != NULL) { #ifdef DEBUG /* printf("... Examining file %s ... \n", subdirentry->d_name); */ #endif /* Ignore non-footprint files found in this directory * We're skipping .png and .html because those * may exist in a library tree to provide an html browsable * index of the library. */ l = strlen (subdirentry->d_name); if (!stat (subdirentry->d_name, &buffer) && S_ISREG (buffer.st_mode) && subdirentry->d_name[0] != '.' && NSTRCMP (subdirentry->d_name, "CVS") != 0 && NSTRCMP (subdirentry->d_name, "Makefile") != 0 && NSTRCMP (subdirentry->d_name, "Makefile.am") != 0 && NSTRCMP (subdirentry->d_name, "Makefile.in") != 0 && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".png") != 0) && (l < 5 || NSTRCMP(subdirentry->d_name + (l - 5), ".html") != 0) && (l < 4 || NSTRCMP(subdirentry->d_name + (l - 4), ".pcb") != 0) ) { #ifdef DEBUG /* printf("... Found a footprint %s ... \n", subdirentry->d_name); */ #endif n_footprints++; entry = GetLibraryEntryMemory (menu); /* * entry->AllocatedMemory points to abs path to the footprint. * entry->ListEntry points to fp name itself. */ len = strlen(subdir) + strlen("/") + strlen(subdirentry->d_name) + 1; entry->AllocatedMemory = (char *)calloc (1, len); strcat (entry->AllocatedMemory, subdir); strcat (entry->AllocatedMemory, PCB_DIR_SEPARATOR_S); /* store pointer to start of footprint name */ entry->ListEntry = entry->AllocatedMemory + strlen (entry->AllocatedMemory); /* Now place footprint name into AllocatedMemory */ strcat (entry->AllocatedMemory, subdirentry->d_name); /* mark as directory tree (newlib) library */ entry->Template = (char *) -1; } } /* Done. Clean up, cd back into old dir, and return */ closedir (subdirobj); if (chdir (olddir)) ChdirErrorMessage (olddir); return n_footprints; }
static int PrintBOM (void) { char utcTime[64]; Coord x, y; double theta = 0.0; double sumx, sumy; int pinfound[MAXREFPINS]; double pinx[MAXREFPINS]; double piny[MAXREFPINS]; double pinangle[MAXREFPINS]; double padcentrex, padcentrey; double centroidx, centroidy; double pin1x, pin1y; int pin_cnt; int found_any_not_at_centroid; int found_any; time_t currenttime; FILE *fp; BomList *bom = NULL; char *name, *descr, *value,*fixed_rotation; int rpindex; fp = fopen (xy_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", xy_filename); return 1; } /* Create a portable timestamp. */ currenttime = time (NULL); { /* avoid gcc complaints */ const char *fmt = "%c UTC"; strftime (utcTime, sizeof (utcTime), fmt, gmtime (¤ttime)); } fprintf (fp, "# PcbXY Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB X-Y\n", UNKNOWN (PCB->Name)); fprintf (fp, "# RefDes, Description, Value, X, Y, rotation, top/bottom\n"); /* don't use localized xy_unit->in_suffix here since */ /* the line itself is not localized and not for GUI */ fprintf (fp, "# X,Y in %s. rotation in degrees.\n", xy_unit->suffix); fprintf (fp, "# --------------------------------------------\n"); /* * For each element we calculate the centroid of the footprint. * In addition, we need to extract some notion of rotation. * While here generate the BOM list */ ELEMENT_LOOP (PCB->Data); { /* Initialize our pin count and our totals for finding the centroid. */ pin_cnt = 0; sumx = 0.0; sumy = 0.0; for (rpindex = 0; rpindex < MAXREFPINS; rpindex++) pinfound[rpindex] = 0; /* Insert this component into the bill of materials list. */ bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)), (char *)UNKNOWN (DESCRIPTION_NAME (element)), (char *)UNKNOWN (VALUE_NAME (element)), bom); /* * Iterate over the pins and pads keeping a running count of how * many pins/pads total and the sum of x and y coordinates * * While we're at it, store the location of pin/pad #1 and #2 if * we can find them. */ PIN_LOOP (element); { sumx += (double) pin->X; sumy += (double) pin->Y; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pin->Number, reference_pin_names[rpindex]) == 0) { pinx[rpindex] = (double) pin->X; piny[rpindex] = (double) pin->Y; pinangle[rpindex] = 0.0; /* pins have no notion of angle */ pinfound[rpindex] = 1; } } } END_LOOP; PAD_LOOP (element); { sumx += (pad->Point1.X + pad->Point2.X) / 2.0; sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0; pin_cnt++; for (rpindex = 0; reference_pin_names[rpindex]; rpindex++) { if (NSTRCMP (pad->Number, reference_pin_names[rpindex]) == 0) { padcentrex = (double) (pad->Point1.X + pad->Point2.X) / 2.0; padcentrey = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; pinx[rpindex] = padcentrex; piny[rpindex] = padcentrey; /* * NOTE: We swap the Y points because in PCB, the Y-axis * is inverted. Increasing Y moves down. We want to deal * in the usual increasing Y moves up coordinates though. */ pinangle[rpindex] = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y, pad->Point2.X - pad->Point1.X); pinfound[rpindex]=1; } } } END_LOOP; if (pin_cnt > 0) { centroidx = sumx / (double) pin_cnt; centroidy = sumy / (double) pin_cnt; if (NSTRCMP( AttributeGetFromList (&element->Attributes,"xy-centre"), "origin") == 0 ) { x = element->MarkX; y = element->MarkY; } else { x = centroidx; y = centroidy; } fixed_rotation = AttributeGetFromList (&element->Attributes, "xy-fixed-rotation"); if (fixed_rotation) { /* The user specified a fixed rotation */ theta = atof (fixed_rotation); found_any_not_at_centroid = 1; found_any = 1; } else { /* Find first reference pin not at the centroid */ found_any_not_at_centroid = 0; found_any = 0; theta = 0.0; for (rpindex = 0; reference_pin_names[rpindex] && !found_any_not_at_centroid; rpindex++) { if (pinfound[rpindex]) { found_any = 1; /* Recenter pin "#1" onto the axis which cross at the part centroid */ pin1x = pinx[rpindex] - x; pin1y = piny[rpindex] - y; /* flip x, to reverse rotation for elements on back */ if (FRONT (element) != 1) pin1x = -pin1x; /* if only 1 pin, use pin 1's angle */ if (pin_cnt == 1) { theta = pinangle[rpindex]; found_any_not_at_centroid = 1; } else if ((pin1x != 0.0) || (pin1y != 0.0)) { theta = xyToAngle (pin1x, pin1y, pin_cnt > 2); found_any_not_at_centroid = 1; } } } if (!found_any) { Message ("PrintBOM(): unable to figure out angle because I could\n" " not find a suitable reference pin of element %s\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } else if (!found_any_not_at_centroid) { Message ("PrintBOM(): unable to figure out angle of element\n" " %s because the reference pin(s) are at the centroid of the part.\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } } name = CleanBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element))); descr = CleanBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element))); value = CleanBOMString ((char *)UNKNOWN (VALUE_NAME (element))); y = PCB->MaxHeight - y; pcb_fprintf (fp, "%m+%s,\"%s\",\"%s\",%.2mS,%.2mS,%g,%s\n", xy_unit->allow, name, descr, value, x, y, theta, FRONT (element) == 1 ? "top" : "bottom"); free (name); free (descr); free (value); } } END_LOOP; fclose (fp); /* Now print out a Bill of Materials file */ fp = fopen (bom_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", bom_filename); print_and_free (NULL, bom); return 1; } fprintf (fp, "# PcbBOM Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB BOM\n", UNKNOWN (PCB->Name)); fprintf (fp, "# Quantity, Description, Value, RefDes\n"); fprintf (fp, "# --------------------------------------------\n"); print_and_free (fp, bom); fclose (fp); return (0); }
/* deal with the "skip" subresource */ static void process_skips (Resource * res) { int type; int i, k; char *sval; int *cnt; char ***lst = NULL; if (res == NULL) return; for (i = 0; i < res->c; i++) { type = resource_type (res->v[i]); switch (type) { case 1: /* * an unnamed sub resource. This is something like * {refdes "J3"} */ sval = res->v[i].subres->v[0].value; if (sval == NULL) { Message ("Error: null skip value\n"); } else { if (NSTRCMP (sval, "refdes") == 0) { cnt = &n_refdes; lst = &ignore_refdes; } else if (NSTRCMP (sval, "value") == 0) { cnt = &n_value; lst = &ignore_value; } else if (NSTRCMP (sval, "descr") == 0) { cnt = &n_descr; lst = &ignore_descr; } else { cnt = NULL; } /* add the entry to the appropriate list */ if (cnt != NULL) { for (k = 1; k < res->v[i].subres->c; k++) { sval = res->v[i].subres->v[k].value; (*cnt)++; if ((*lst = (char **) realloc (*lst, (*cnt) * sizeof (char *))) == NULL) { fprintf (stderr, "realloc() failed\n"); exit (-1); } (*lst)[*cnt - 1] = strdup (sval); } } } break; default: Message (_("Ignored resource type = %d in skips= section\n"), type); } } }
static void InitPaths (char *argv0) { size_t l; int i; int haspath; char *t1, *t2; int found_bindir = 0; /* see if argv0 has enough of a path to let lrealpath give the * real path. This should be the case if you invoke pcb with * something like /usr/local/bin/pcb or ./pcb or ./foo/pcb * but if you just use pcb and it exists in your path, you'll * just get back pcb again. */ #ifdef FAKE_BINDIR haspath = 1; #else haspath = 0; for (i = 0; i < strlen (argv0) ; i++) { if (argv0[i] == PCB_DIR_SEPARATOR_C) haspath = 1; } #endif #ifdef DEBUG printf ("InitPaths (%s): haspath = %d\n", argv0, haspath); #endif if (haspath) { #ifdef FAKE_BINDIR bindir = strdup(FAKE_BINDIR "/"); #else bindir = strdup (lrealpath (argv0)); #endif found_bindir = 1; } else { char *path, *p, *tmps; struct stat sb; int r; tmps = getenv ("PATH"); if (tmps != NULL) { path = strdup (tmps); /* search through the font path for a font file */ for (p = strtok (path, PCB_PATH_DELIMETER); p && *p; p = strtok (NULL, PCB_PATH_DELIMETER)) { #ifdef DEBUG printf ("Looking for %s in %s\n", argv0, p); #endif if ( (tmps = (char *)malloc ( (strlen (argv0) + strlen (p) + 2) * sizeof (char))) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (tmps, "%s%s%s", p, PCB_DIR_SEPARATOR_S, argv0); r = stat (tmps, &sb); if (r == 0) { #ifdef DEBUG printf ("Found it: \"%s\"\n", tmps); #endif bindir = lrealpath (tmps); found_bindir = 1; free (tmps); break; } free (tmps); } free (path); } } #ifdef DEBUG printf ("InitPaths(): bindir = \"%s\"\n", bindir); #endif if (found_bindir) { /* strip off the executible name leaving only the path */ t2 = NULL; t1 = strchr (bindir, PCB_DIR_SEPARATOR_C); while (t1 != NULL && *t1 != '\0') { t2 = t1; t1 = strchr (t2 + 1, PCB_DIR_SEPARATOR_C); } if (t2 != NULL) *t2 = '\0'; #ifdef DEBUG printf ("After stripping off the executible name, we found\n"); printf ("bindir = \"%s\"\n", bindir); #endif } else { /* we have failed to find out anything from argv[0] so fall back to the original * install prefix */ bindir = strdup (BINDIR); } /* now find the path to exec_prefix */ l = strlen (bindir) + 1 + strlen (BINDIR_TO_EXECPREFIX) + 1; if ( (exec_prefix = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (exec_prefix, "%s%s%s", bindir, PCB_DIR_SEPARATOR_S, BINDIR_TO_EXECPREFIX); /* now find the path to PCBSHAREDIR */ l = strlen (bindir) + 1 + strlen (BINDIR_TO_PCBSHAREDIR) + 1; if ( (pcblibdir = (char *) malloc (l * sizeof (char) )) == NULL ) { fprintf (stderr, "InitPaths(): malloc failed\n"); exit (1); } sprintf (pcblibdir, "%s%s%s", bindir, PCB_DIR_SEPARATOR_S, BINDIR_TO_PCBSHAREDIR); #ifdef DEBUG printf ("bindir = %s\n", bindir); printf ("pcblibdir = %s\n", pcblibdir); #endif l = sizeof (main_attribute_list) / sizeof (main_attribute_list[0]); for (i = 0; i < l ; i++) { if (NSTRCMP (main_attribute_list[i].name, "lib-command-dir") == 0) { main_attribute_list[i].default_val.str_value = pcblibdir; } if ( (NSTRCMP (main_attribute_list[i].name, "font-path") == 0) || (NSTRCMP (main_attribute_list[i].name, "element-path") == 0) || (NSTRCMP (main_attribute_list[i].name, "lib-path") == 0) ) { main_attribute_list[i].default_val.str_value = pcblibdir; } } { char *tmps; tmps = getenv ("HOME"); if (tmps == NULL) { tmps = getenv ("USERPROFILE"); } if (tmps != NULL) { homedir = strdup (tmps); } else { homedir = NULL; } } resolve_all_paths(fontfile_paths_in, fontfile_paths); }
static int PrintBOM (void) { char utcTime[64]; Coord x, y; double theta = 0.0; double sumx, sumy; double pin1x = 0.0, pin1y = 0.0, pin1angle = 0.0; double pin2x = 0.0, pin2y = 0.0; int found_pin1; int found_pin2; int pin_cnt; time_t currenttime; FILE *fp; BomList *bom = NULL; char *name, *descr, *value; fp = fopen (xy_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", xy_filename); return 1; } /* Create a portable timestamp. */ currenttime = time (NULL); { /* avoid gcc complaints */ const char *fmt = "%c UTC"; strftime (utcTime, sizeof (utcTime), fmt, gmtime (¤ttime)); } fprintf (fp, "# PcbXY Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB X-Y\n", UNKNOWN (PCB->Name)); fprintf (fp, "# RefDes, Description, Value, X, Y, rotation, top/bottom\n"); fprintf (fp, "# X,Y in %s. rotation in degrees.\n", xy_unit->in_suffix); fprintf (fp, "# --------------------------------------------\n"); /* * For each element we calculate the centroid of the footprint. * In addition, we need to extract some notion of rotation. * While here generate the BOM list */ ELEMENT_LOOP (PCB->Data); { /* initialize our pin count and our totals for finding the centriod */ pin_cnt = 0; sumx = 0.0; sumy = 0.0; found_pin1 = 0; found_pin2 = 0; /* insert this component into the bill of materials list */ bom = bom_insert ((char *)UNKNOWN (NAMEONPCB_NAME (element)), (char *)UNKNOWN (DESCRIPTION_NAME (element)), (char *)UNKNOWN (VALUE_NAME (element)), bom); /* * iterate over the pins and pads keeping a running count of how * many pins/pads total and the sum of x and y coordinates * * While we're at it, store the location of pin/pad #1 and #2 if * we can find them */ PIN_LOOP (element); { sumx += (double) pin->X; sumy += (double) pin->Y; pin_cnt++; if (NSTRCMP (pin->Number, "1") == 0) { pin1x = (double) pin->X; pin1y = (double) pin->Y; pin1angle = 0.0; /* pins have no notion of angle */ found_pin1 = 1; } else if (NSTRCMP (pin->Number, "2") == 0) { pin2x = (double) pin->X; pin2y = (double) pin->Y; found_pin2 = 1; } } END_LOOP; PAD_LOOP (element); { sumx += (pad->Point1.X + pad->Point2.X) / 2.0; sumy += (pad->Point1.Y + pad->Point2.Y) / 2.0; pin_cnt++; if (NSTRCMP (pad->Number, "1") == 0) { pin1x = (double) (pad->Point1.X + pad->Point2.X) / 2.0; pin1y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; /* * NOTE: We swap the Y points because in PCB, the Y-axis * is inverted. Increasing Y moves down. We want to deal * in the usual increasing Y moves up coordinates though. */ pin1angle = (180.0 / M_PI) * atan2 (pad->Point1.Y - pad->Point2.Y, pad->Point2.X - pad->Point1.X); found_pin1 = 1; } else if (NSTRCMP (pad->Number, "2") == 0) { pin2x = (double) (pad->Point1.X + pad->Point2.X) / 2.0; pin2y = (double) (pad->Point1.Y + pad->Point2.Y) / 2.0; found_pin2 = 1; } } END_LOOP; if (pin_cnt > 0) { x = sumx / (double) pin_cnt; y = sumy / (double) pin_cnt; if (found_pin1) { /* recenter pin #1 onto the axis which cross at the part centroid */ pin1x -= x; pin1y -= y; pin1y = -1.0 * pin1y; /* if only 1 pin, use pin 1's angle */ if (pin_cnt == 1) theta = pin1angle; else { /* if pin #1 is at (0,0) use pin #2 for rotation */ if ((pin1x == 0.0) && (pin1y == 0.0)) { if (found_pin2) theta = xyToAngle (pin2x, pin2y); else { Message ("PrintBOM(): unable to figure out angle of element\n" " %s because pin #1 is at the centroid of the part.\n" " and I could not find pin #2's location\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } } else theta = xyToAngle (pin1x, pin1y); } } /* we did not find pin #1 */ else { theta = 0.0; Message ("PrintBOM(): unable to figure out angle because I could\n" " not find pin #1 of element %s\n" " Setting to %g degrees\n", UNKNOWN (NAMEONPCB_NAME (element)), theta); } name = CleanBOMString ((char *)UNKNOWN (NAMEONPCB_NAME (element))); descr = CleanBOMString ((char *)UNKNOWN (DESCRIPTION_NAME (element))); value = CleanBOMString ((char *)UNKNOWN (VALUE_NAME (element))); y = PCB->MaxHeight - y; pcb_fprintf (fp, "%m+%s,\"%s\",\"%s\",%mS,%.2mS,%g,%s\n", xy_unit->allow, name, descr, value, x, y, theta, FRONT (element) == 1 ? "top" : "bottom"); free (name); free (descr); free (value); } } END_LOOP; fclose (fp); /* Now print out a Bill of Materials file */ fp = fopen (bom_filename, "w"); if (!fp) { gui->log ("Cannot open file %s for writing\n", bom_filename); print_and_free (NULL, bom); return 1; } fprintf (fp, "# PcbBOM Version 1.0\n"); fprintf (fp, "# Date: %s\n", utcTime); fprintf (fp, "# Author: %s\n", pcb_author ()); fprintf (fp, "# Title: %s - PCB BOM\n", UNKNOWN (PCB->Name)); fprintf (fp, "# Quantity, Description, Value, RefDes\n"); fprintf (fp, "# --------------------------------------------\n"); print_and_free (fp, bom); fclose (fp); return (0); }
bool vendorIsElementMappable (ElementType *element) { int i; int noskip; if (vendorMapEnable == false) return false; noskip = 1; for (i = 0; i < n_refdes; i++) { if ((NSTRCMP (UNKNOWN (NAMEONPCB_NAME (element)), ignore_refdes[i]) == 0) || rematch (ignore_refdes[i], UNKNOWN (NAMEONPCB_NAME (element)))) { Message (_ ("Vendor mapping skipped because refdes = %s matches %s\n"), UNKNOWN (NAMEONPCB_NAME (element)), ignore_refdes[i]); noskip = 0; } } if (noskip) for (i = 0; i < n_value; i++) { if ((NSTRCMP (UNKNOWN (VALUE_NAME (element)), ignore_value[i]) == 0) || rematch (ignore_value[i], UNKNOWN (VALUE_NAME (element)))) { Message (_ ("Vendor mapping skipped because value = %s matches %s\n"), UNKNOWN (VALUE_NAME (element)), ignore_value[i]); noskip = 0; } } if (noskip) for (i = 0; i < n_descr; i++) { if ((NSTRCMP (UNKNOWN (DESCRIPTION_NAME (element)), ignore_descr[i]) == 0) || rematch (ignore_descr[i], UNKNOWN (DESCRIPTION_NAME (element)))) { Message (_ ("Vendor mapping skipped because descr = %s matches %s\n"), UNKNOWN (DESCRIPTION_NAME (element)), ignore_descr[i]); noskip = 0; } } if (noskip && TEST_FLAG (LOCKFLAG, element)) { Message (_("Vendor mapping skipped because element %s is locked\n"), UNKNOWN (NAMEONPCB_NAME (element))); noskip = 0; } if (noskip) return true; else return false; }