#usage "Library Merge

\n" "This ULP will copy packages, symbols, and/or devices from one library to another. " "The user must run this ULP with the destination library open. It will then copy " "all of the symbols/packages/devices to a temporary file and then open the source " "library. It will list all of the symbols/packages/devices in the source library " "that don't have an identical name in the destination. The user can select any or " "all of the devices and then hit copy. The ULP will then generate a export file of " "those devices. It will re-open the destination library and import them. " "Jim Thurman tlj@pcez.com " string HelpText = "This ULP will copy packages, symbols, and/or devices from one library to another. " "The user must run this ULP with the destination library open. It will then copy " "all of the symbols/packages/devices to a temporary file and then open the source " "library. It will list all of the symbols/packages/devices in the source library " "that don't have an identical name in the destination. The user can select any or " "all of the devices and then hit copy. The ULP will then generate a export file of " "those devices. It will re-open the destination library and import them. It checks " "each device selected to be certain that symbols and packages that are a part of that " "device are in the destination library or selected from the source. If not it gives " "the user the opportunity to copy these symbol/packages as well. If you select the " "same library for source as the one already open (destination) the list of " "symbol/package/devices will be empty as they all match. If you terminate the ULP " "by quiting the dialog box you will have the source library open, not the original " "destination." "<\p>" "This program can generate an export script of all or part of any library enabling " "the possibility of selecting some symbol/package/devices from one or more libraries " "to generate a completely new one. Not every possible object in a library is handled " "at present but it does a good job of duplicating the libraries I tried. " "<\p>" "This program came from 'lbr_man_1_2.ulp' which seemed to want to do a similar thing " "but didn't have the script export function done. Oppologies in advance if I find myself " "without sufficient time to finish documenting the program and just upload it. " "<\p>" "NOTE: this program generates 1 temporary script file (Temp~1.scr) when the source library " "is selected and another when the copy button is pushed (Temp~2.scr). Also the file " "'DestLibData.tmp' which contains the names of the symbols, packages, and device sets in " "the destination library." ; int CurrentLayer; // last layer command written out so won't be duplicated in output int CurrentStyle; // last line style written out int CurrentFont; // last font int CurrentRatio; // last ratio real CurrentSize; // last text size real CurrentDrill; // last drill size int ListElement; // number of elements in display list int DstPackageNum,DstSymbolNum,DstDeviceNum; // number of elements in destination symbol/package/device arrays int SrcPackageNum,SrcSymbolNum,SrcDeviceNum; // number of elements in source symbol/package/device arrays string DstPackage[],DstSymbol[],DstDevice[]; // destination library symbol/package/device names string SrcPackage[],SrcSymbol[],SrcDevice[]; // source library symbol/package/device names string List[]; // displayed list //****************************************************************************************************** // writes out the help box //****************************************************************************************************** void DisplayHelp(void) { dlgDialog("Library Merge Help") { dlgHBoxLayout dlgSpacing(400); dlgHBoxLayout { dlgVBoxLayout dlgSpacing(300); dlgTextView(HelpText); } dlgHBoxLayout { dlgStretch(1); dlgPushButton("-Close") dlgReject(); } }; } //****************************************************************************************************** // get file path of any file open. //****************************************************************************************************** string get_project_path() { if (library) library(B) return(filedir(B.name)); if (board) board(B) return(filedir(B.name)); if (schematic) schematic(B) return(filedir(B.name)); } //****************************************************************************************************** // right trim string of spaces //****************************************************************************************************** string StrRTrim(string Str) { int x; x=strlen(Str)-1; while ((x>=0) && (Str[x]==' ')) { Str[x--]=0; } return(Str); } //************************************************************************************************** // turn all last script output values off //************************************************************************************************** void ResetGlobals(void) { CurrentLayer=-1; // no last layer sent CurrentStyle=-1; // no last line style CurrentSize=-1; // no last text size CurrentFont=-1; // no last font CurrentRatio=-1; // no last ratio CurrentDrill=-1; // no last drill size } //************************************************************************************************** // If new layer not the current one, then change. //************************************************************************************************** void ChangeLayer(int NewLayer) { if (NewLayer!=CurrentLayer) { CurrentLayer=NewLayer; printf("Layer %d;\n",NewLayer); } } //************************************************************************************************** // If the new drill size is different then the current one then change. //************************************************************************************************** void ChangeDrill(real NewDrill) { if (NewDrill!=CurrentDrill) { CurrentDrill=NewDrill; printf("Change Drill %f;\n",CurrentDrill); } } //************************************************************************************************** // The wire styles are stored as numbers by are written as text for scripts //************************************************************************************************** string WireStyleToText(int style) { string str1; switch (style) { case WIRE_STYLE_CONTINUOUS: str1="continuous"; break; case WIRE_STYLE_LONGDASH: str1="longdash"; break; case WIRE_STYLE_SHORTDASH: str1="shortdash"; break; case WIRE_STYLE_DASHDOT: str1="dashdot"; break; default: str1="*INVALID"; break; } return(str1); } //************************************************************************************************** // If the wire style is different then the current one then change //************************************************************************************************** void ChangeStyle(int NewStyle) { if (NewStyle!=CurrentStyle) { CurrentStyle=NewStyle; printf("Change Style %s;\n",WireStyleToText(NewStyle)); } } //************************************************************************************************** // If the new text size is different than the current one, change. //************************************************************************************************** void ChangeSize(real NewSize) { if (NewSize!=CurrentSize) { CurrentSize=NewSize; printf("Change Size %f;\n",NewSize); } } //************************************************************************************************** // If the new text ratio is different than current, change. //************************************************************************************************** void CheckRatio(int NewRatio) { if (NewRatio!=CurrentRatio) { CurrentRatio=NewRatio; printf("Change Ratio %d;\n",NewRatio); } } //************************************************************************************************** // Font codes are numberic internally but text in scripts //************************************************************************************************** string FontToText(int font) { string str1; switch(font) { case FONT_VECTOR: str1="Vector"; break; case FONT_PROPORTIONAL: str1="Proportional"; break; case FONT_FIXED: str1="Fixed"; break; } return(str1); } //************************************************************************************************** // if the new font is different than change it. //************************************************************************************************** void CheckFont(int NewFont) { if (NewFont!=CurrentFont) { CurrentFont=NewFont; printf("Change Font %s;\n",FontToText(NewFont)); } } //************************************************************************************************** // convert the numeric pad shape code to text //************************************************************************************************** string PadShapeToText(int PadShape) { string str1; switch(PadShape) { case PAD_SHAPE_SQUARE: str1="Square"; break; case PAD_SHAPE_ROUND: str1="Round"; break; case PAD_SHAPE_OCTAGON: str1="Octagon"; break; case PAD_SHAPE_LONG: str1="Long"; break; case PAD_SHAPE_OFFSET: str1="Offset"; break; case PAD_SHAPE_ANNULUS: str1="Annulus"; break; // (only if supply layers are used) case PAD_SHAPE_THERMAL: str1="Thermal"; break; // (only if supply layers are used) default: str1="INVALID"; break; } return(str1); } //************************************************************************************************** // generate a text equivelent of the angle information //************************************************************************************************** string AngleToText(real f,int MirrorFlag,int SpinFlag) { int i; string str1,str2,str3; i=f; if (SpinFlag) str1="S"; else str1=""; if (MirrorFlag) str2="M"; else str2=""; sprintf(str3,"%s%sR%d",str1,str2,i); return(str3); } //************************************************************************************************** // print the script information related to a pad //************************************************************************************************** void PrintPad(UL_PAD Pad1,int layer1) { real d,x,y,drill; d=Pad1.diameter[layer1]; d=d/10000; x=Pad1.x; y=Pad1.y; x=x/10000; y=y/10000; drill=Pad1.drill; drill=drill/10000; ChangeDrill(drill); printf("Pad '%s' %s %f (%f %f);\n",Pad1.name,PadShapeToText(Pad1.shape[layer1]),d,x,y); } //************************************************************************************************** // print the script information related for a smd //************************************************************************************************** void PrintSmd(UL_SMD Smd,int layer1) { real dx,dy,x,y; string flagstr; dx=Smd.dx[Smd.layer]; dy=Smd.dy[Smd.layer]; dx=dx/10000; dy=dy/10000; x=Smd.x; y=Smd.y; x=x/10000; y=y/10000; flagstr=""; if ((Smd.flags & SMD_FLAG_STOP)==0) flagstr=flagstr+"NOSTOP "; if ((Smd.flags & SMD_FLAG_THERMALS)==0) flagstr=flagstr+"NOTHERMALS "; if ((Smd.flags & SMD_FLAG_CREAM)==0) flagstr=flagstr+"NOCREAM"; ChangeLayer(Smd.layer); printf("Smd '%s' %f %f -%d R%f %s (%f %f);\n",Smd.name,dx,dy,Smd.roundness,Smd.angle,flagstr,x,y); } //************************************************************************************************** // print the script information related for a contact which can be a pad or smd //************************************************************************************************** void PrintContact(UL_CONTACT Cont) { if (Cont.pad) PrintPad(Cont.pad,LAYER_PADS); if (Cont.smd) PrintSmd(Cont.smd,LAYER_TOP); } //************************************************************************************************** // convert the direction code to script text //************************************************************************************************** string DirectionToText(int dir) { string str1; switch (dir) { case PIN_DIRECTION_NC: str1="NC"; break; case PIN_DIRECTION_IN: str1="In"; break; case PIN_DIRECTION_OUT: str1="Out"; break; case PIN_DIRECTION_IO: str1="I/O"; break; case PIN_DIRECTION_OC: str1="OC"; break; case PIN_DIRECTION_PWR: str1="Pwr"; break; case PIN_DIRECTION_PAS: str1="Pas"; break; case PIN_DIRECTION_HIZ: str1="Hiz"; break; case PIN_DIRECTION_SUP: str1="Sup"; break; } return(str1); } //************************************************************************************************** // convert the function code to text //************************************************************************************************** string FunctionToText(int fun) { string str1; switch (fun) { case PIN_FUNCTION_FLAG_NONE: str1="None"; break; case PIN_FUNCTION_FLAG_DOT: str1="Dot"; break; case PIN_FUNCTION_FLAG_CLK: str1="Clk"; break; } return(str1); } //************************************************************************************************** // convert pin length code to text //************************************************************************************************** string PinLengthToText(int fun) { string str1; switch (fun) { case PIN_LENGTH_POINT: str1="Point"; break; case PIN_LENGTH_SHORT: str1="Short"; break; case PIN_LENGTH_MIDDLE: str1="Middle"; break; case PIN_LENGTH_LONG: str1="Long"; break; } return(str1); } //************************************************************************************************** // convert the pad/pin visible flags to text //************************************************************************************************** string PinVisibleToText(int PinVisibleFlag) { string str1; if (PinVisibleFlag & PIN_VISIBLE_FLAG_PAD) { if (PinVisibleFlag & PIN_VISIBLE_FLAG_PIN) str1="Both"; else str1="Pad"; } else { if (PinVisibleFlag & PIN_VISIBLE_FLAG_PIN) str1="Pin"; else str1="Off"; } return(str1); } //************************************************************************************************** // convert a name to a form that can be written out (no spaces or single quotes by themselves. //************************************************************************************************** string CheckName(string name) { int x; string str1; str1=name; x=0; while (x>=0) { x=strchr(str1,'\'',x); if (x>=0) { str1=strsub(str1,0,x+1)+"\'"+strsub(str1,x+1,strlen(str1)-x-1); x=x+2; if (x>=strlen(str1)) x=-1; } else { x=strchr(str1,' ',0); if (x>=0) { str1=strsub(str1,0,x)+"_*_"+strsub(str1,x+1,strlen(str1)-x); x=x+4; if (x>=strlen(str1)) x=-1; } } } return(str1); } //************************************************************************************************** // remove carriage returns from string and replace with 'continute line'. //************************************************************************************************** string DescriptionToPrint(string desc) { int x; string str1; str1=desc; x=0; while (x>=0) { x=strchr(str1,'\n',x); if (x>=0) { str1=strsub(str1,0,x)+"\\"+strsub(str1,x,strlen(str1)-x); x=x+2; if (x>=strlen(str1)) x=-1; } } return(str1); } //************************************************************************************************** // replace carriage return or tab with space. //************************************************************************************************** string DescriptionToDisplay(string desc,int maxlen) { int x; string str1; str1=desc; if (strlen(str1)>maxlen) str1[maxlen-1]=0; x=0; while (x>=0) { x=strchr(str1,'\n',x); if (x>=0) { str1[x]=' '; } x=strchr(str1,'\t',x); if (x>=0) { str1[x]=' '; } } return(str1); } //************************************************************************************************** // print the script command for pin generation //************************************************************************************************** void PrintPin(UL_PIN Pin) { real x,y; x=Pin.x; y=Pin.y; x=x/10000; y=y/10000; printf("Pin '%s' %s %s %s %s %s %d (%f %f);\n",CheckName(Pin.name),DirectionToText(Pin.direction),FunctionToText(Pin.function), PinLengthToText(Pin.length),AngleToText(Pin.angle,0,0),PinVisibleToText(Pin.visible),Pin.swaplevel,x, y); } //************************************************************************************************** // print the script information associated with a 'Area' data element //************************************************************************************************** void PrintArea(UL_AREA Area) { printf("Area: (%d %d), (%d %d)\n",Area.x1, Area.y1, Area.x2, Area.y2); } //************************************************************************************************** // print the script information associated with a 'Circle' data element //************************************************************************************************** void PrintCircles(UL_CIRCLE Circle) { ChangeLayer(Circle.layer); printf("Circle %d (%d %d) (%d 0);\n", Circle.width,Circle.x, Circle.y, Circle.radius); } //************************************************************************************************** // print the script information associated with a 'Rectangle' data element //************************************************************************************************** void PrintRectangle(UL_RECTANGLE Rect) { real x1,y1,x2,y2; ChangeLayer(Rect.layer); x1=Rect.x1; y1=Rect.y1; x2=Rect.x2; y2=Rect.y2; x1=x1/10000; y1=y1/10000; x2=x2/10000; y2=y2/10000; printf("Rect %s (%f %f) (%f %f);\n",AngleToText(Rect.angle,0,0),x1,y1,x2,y2); } //************************************************************************************************** // convert arc cap code to text //************************************************************************************************** string CapToText(int cap) { string str1; switch (cap) { case CAP_FLAT: str1="Flat"; break; case CAP_ROUND: str1="Round"; break; default: str1=""; break; } return(str1); } //************************************************************************************************** // print script data related to an arc //************************************************************************************************** void PrintArc(UL_ARC Arc) { ChangeLayer(Arc.layer); printf("Arc: %f %f %s %d %d (%d %d) (%d %d) (%d %d)\n",Arc.angle1,Arc.angle2,CapToText(Arc.cap),Arc.radius, Arc.width,Arc.x1,Arc.y1,Arc.x2,Arc.y2,Arc.xc,Arc.yc); } //************************************************************************************************** // print script data related to a wire segment //************************************************************************************************** void PrintOneWire(UL_WIRE Wire) { printf("Wire: %d %f %d %d %d (%d %d) (%d %d)\n",Wire.cap,Wire.curve,Wire.layer,Wire.style,Wire.width, Wire.x1,Wire.y1,Wire.x2,Wire.y2); // if (Wire.arc) PrintArc(Wire.arc); } //************************************************************************************************** // print script data related to an wire //************************************************************************************************** void PrintWire(UL_WIRE Wire) { string str1; real f,x1,y1,x2,y2; ChangeLayer(Wire.layer); ChangeStyle(Wire.style); f=Wire.width; f=f/10000; x1=Wire.x1; y1=Wire.y1; x2=Wire.x2; y2=Wire.y2; x1=x1/10000; y1=y1/10000; x2=x2/10000; y2=y2/10000; printf("Wire %f (%f %f) %s %+f (%f %f);\n",f,x1,y1,CapToText(Wire.cap),Wire.curve,x2,y2); Wire.pieces(piece) { } } //************************************************************************************************** // print script data related to an polygon //************************************************************************************************** void PrintPolygon(UL_POLYGON Poly) { real w; w=Poly.width; w=w/10000; ChangeLayer(Poly.layer); printf("Polygon %f;\n",w); Poly.contours(Conts) { PrintWire(Conts); } Poly.fillings(Fills) { PrintWire(Fills); } Poly.wires(wires) { PrintWire(wires); } } //************************************************************************************************** // print script data related to text //************************************************************************************************** void PrintText(UL_TEXT Text1) { real f,x,y; ChangeLayer(Text1.layer); f=Text1.size; f=f/10000; ChangeSize(f); CheckRatio(Text1.ratio); CheckFont(Text1.font); x=Text1.x; y=Text1.y; x=x/10000; y=y/10000; printf("Text '%s' %s (%f %f);\n",Text1.value,AngleToText(Text1.angle,Text1.mirror,Text1.spin),x,y); } //************************************************************************************************** //************************************************************************************************** void PrintCircle(UL_CIRCLE Circle) { } //************************************************************************************************** // print script data related to a hole //************************************************************************************************** void PrintHole(UL_HOLE Hole,int layer) { real drill; drill=Hole.drill; drill=drill/10000; ChangeDrill(drill); } //************************************************************************************************** // print all script data defining a package //************************************************************************************************** void PrintPackage(UL_PACKAGE Package) { printf("Edit %s.pac;\n",CheckName(Package.name)); printf("Description '%s';\n",DescriptionToPrint(Package.description)); Package.holes(hole) { PrintHole(hole,LAYER_TSTOP); } Package.circles(circle) { PrintCircle(circle); } Package.contacts(contact) { PrintContact(contact); } Package.polygons(polygon) { PrintPolygon(polygon); } Package.rectangles(rectangle) { PrintRectangle(rectangle); } Package.texts(text) { PrintText(text); } Package.wires(wire) { PrintWire(wire); } } //************************************************************************************************** // change layer number //************************************************************************************************** void PrintLayer(UL_LAYER Layer) { printf("Layer %d %s;\n",Layer.number,Layer.name); } //************************************************************************************************** // print all script data defining a sumbol //************************************************************************************************** void PrintSymbol(UL_SYMBOL Symbol) { printf("Edit %s.sym;\n",CheckName(Symbol.name)); Symbol.circles(circle) { PrintCircle(circle); } Symbol.rectangles(rect) { PrintRectangle(rect); } Symbol.pins(pin) { PrintPin(pin); } Symbol.polygons(poly) { PrintPolygon(poly); } Symbol.texts(text) { PrintText(text); } Symbol.wires(wire) { PrintWire(wire); } } //************************************************************************************************** // convert add level code to text //************************************************************************************************** string AddLevelToText(int AddLevel) { string str1; switch(AddLevel) { case GATE_ADDLEVEL_MUST: str1="Must"; break; case GATE_ADDLEVEL_CAN: str1="Can"; break; case GATE_ADDLEVEL_NEXT: str1="Next"; break; case GATE_ADDLEVEL_REQUEST: str1="Request"; break; case GATE_ADDLEVEL_ALWAYS: str1="Always"; break; default: str1="INVALID"; break; } return(str1); } //************************************************************************************************** // print script form of gate definition //************************************************************************************************** void PrintGate(UL_GATE Gate,string devname) { real x,y; x=Gate.x; y=Gate.y; x=x/10000; y=y/10000; printf("Add %s '%s' %s %d (%f %f);\n",devname,Gate.name,AddLevelToText(Gate.addlevel),Gate.swaplevel,x,y); } //************************************************************************************************** // print all script data defining a device set //************************************************************************************************** void PrintDeviceSet(UL_DEVICESET DeviceSet) { int GateNum,Variant; real x,y; GateNum=0; printf("Edit %s.dev;\n",CheckName(DeviceSet.name)); printf("Prefix '%s';\n",DeviceSet.prefix); printf("Description '%s';\n",DescriptionToPrint(DeviceSet.description)); printf("Value %s;\n",DeviceSet.value); DeviceSet.devices(device) { Variant++; if (device.package) { printf("Package '%s' '%s';\n",device.package.name,device.name); printf("Technology %s;\n",device.technologies); } device.gates(gate) { GateNum++; x=gate.x; y=gate.y; x=x/10000; y=y/10000; if (Variant==1) { printf("Add %s '%s' %s %d (%f %f);\n",CheckName(gate.symbol.name),CheckName(gate.name),AddLevelToText(gate.addlevel),gate.swaplevel,x,y); } gate.symbol.pins(pin) { if (pin.contact) { printf("Connect '%s.%s' '%s';\n",CheckName(gate.name),CheckName(pin.name),pin.contact.name); } } } } } //************************************************************************************************** // convert the grid unit code to text //************************************************************************************************** string GridUnitToString(int GridUnit) { string str1; switch(GridUnit) { case GRID_UNIT_MIC: str1="mic"; break; case GRID_UNIT_MM: str1="mm"; break; case GRID_UNIT_MIL: str1="mil"; break; case GRID_UNIT_INCH: str1="inch"; break; default: str1="INVALID"; break; } return(str1); } //************************************************************************************************** // print grid. This is fixed information as the data returned from the library is wrong. Many // dimensions are fixed in millimeters. //************************************************************************************************** void PrintGrid(UL_GRID Grid) { printf("Grid mm;\n"); } //************************************************************************************************** // print all script data defining a library //************************************************************************************************** void PrintLibrary(UL_LIBRARY Library) { string str1; int Result; status("Print Grid"); PrintGrid(Library.grid); status(" Print Layers"); Library.layers(layer) { PrintLayer(layer); } printf("Description '%s';\n",DescriptionToPrint(Library.description)); status(" Print Symbols"); Library.symbols(symbol1) { ResetGlobals(); printf("\n"); PrintSymbol(symbol1); } status(" Print packages"); Library.packages(package1) { ResetGlobals(); printf("\n"); PrintPackage(package1); } status("Print Device Sets"); Library.devicesets(device_set) { printf("\n"); PrintDeviceSet(device_set); } } //************************************************************************************************** //************************************************************************************************** void ToggleStatus(string ElementType) { int x; string TempAry[]; for (x=0;x0) WorkPath=strsub(WorkPath,0,x+2); // if there is a colon then this is just the drive and root '\' FirstArgument=""; if (argc>0) FirstArgument=argv[1]; // run number argument, if any RunNum=strtol(FirstArgument); switch(RunNum) { case 0: // first iteration if (library) { // check to see if a library file is open library(DestLibrary) { // assign a variable to this library EditName=filename(DestLibrary.name); // name of loaded library w/o path output(WorkPath+"DestLibData.tmp", "wt") { // create a temporary file of this library DestLibrary.symbols(S) printf("S\t%s\n",StrRTrim(S.name)/*,StrRTrim(S.description)*/); // write out all symbol names DestLibrary.packages(P) printf("P\t%s\n",StrRTrim(P.name)/*,StrRTrim(P.description)*/); // write out packages names DestLibrary.devicesets(D) printf("D\t%s\n",StrRTrim(D.name)/*,StrRTrim(D.description)*/);// write out device names } }; SourceFileName = dlgFileOpen("Select source library", SourceFileName, "*.lbr"); // activate the dialog box to select the source library if (SourceFileName != "") { output(WorkPath+"Temp~1.scr", "wt") { // create/edit the script file to invoke this ULP with the destination library open printf("OPEN \'%s\';\n",SourceFileName); // open the source library file printf("RUN '%s' 1 '%s';\n",ProgName,EditName); // run this program with a '1' for the run number }; sprintf(TempStr,"script %sTemp~1.scr",WorkPath); // script name to run on exit exit(TempStr); // exit this interation and run the temporary script } } else { dlgMessageBox("ERROR


This program can only work in the library editor."); } break; case 1: // this is the second iteration of this ULP with the source library file open through script 'Temp~1' library(SourceLibrary) { // assign a variable to library data status("Loading Source File"); // indicate that we are loading the source file in the status box Length=fileread(FileInData,WorkPath+"DestLibData.tmp"); // read in destination library data DstSymbolNum=0; // number of symbols in destination library DstPackageNum=0; // number of symbols in destination library DstDeviceNum=0; // number of devices in destination library for (x=0;x