Guest User

Untitled

a guest
Nov 23rd, 2015
85
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. string Version = "2.02";
  2.  
  3. #usage " \
  4. <b>Export a Bill Of Materials / Real-Time Pricing / Online Ordering</b> \
  5. <p> \
  6. Generates a project's bill Of materials (BOM). \
  7. <p> \
  8. In addition, BOMs are genrated that can be imported directly into the Digi-Key and Mouser website ordering systems. \
  9. Also, <b>quantity-based component pricing can be fetched directly from the \
  10. Digi-Key website</b> for a quick estimate of circuit cost. \
  11. <p> \
  12. <author>Author: support@cadsoft.de<br> \
  13. Modified by: Dave Vandenbout / XESS Corp. - devb@xess.com</author> \
  14. Modified by: charliex / NUll Space Labs - charlie@x.io</author> \
  15. <p> \
  16. Version: 2.02 \
  17. "
  18.  
  19.  
  20. //==================================================================================================
  21. // TODO List:
  22. // 0. Don't make a career out of this.
  23. // 1. Extract pricing info from Mouser.
  24. // 2. Integrate Octopart.
  25. //==================================================================================================
  26.  
  27.  
  28. // THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
  29.  
  30. // We need these strings in the help text.
  31. string DigikeyBomWebPage = "https://ordering.digikey.com/registereduser/BOMWizard.aspx";
  32. string MouserBomWebPage = "http://www.mouser.com/tools/tools.aspx";
  33.  
  34. string HelpText = " \
  35. <h1>How to Generate the Bill Of Materials</h1> \
  36. <h2><a name=\"Build_Quantity\">Build Quantity</a></h2> \
  37. <p>Enter the number of boards to be built in the <b>Build Quantity</b> field. \
  38. <h2><a name=\"List_Types\">List Types</a></h2> \
  39. <p> \
  40. The BOM format is selected by clicking one of the following radio buttons. \
  41. <ul> \
  42. <li> \
  43. <b>Parts:</b> The BOM consists of a list of parts with each part on its own line. \
  44. </li> \
  45. <li> \
  46. <b>Values:</b> The BOM consists of a list of values where all the parts with \
  47. the same value are grouped together on one line. \
  48. </li> \
  49. <li> \
  50. <b>Manf:</b> This BOM format is similar to Values with the addition of the \
  51. manufacturer's name and their part number. This format is useful for sending to distributors to get quotes. \
  52. </li> \
  53. <li> \
  54. <b>Manf+Distributors:</b> This BOM format is similar to Manf with the \
  55. ordering codes for both Digi-Key and Mouser added. \
  56. </li> \
  57. <li> \
  58. <b>Digi-Key Order:</b> This generates a parts list that can be input directly into \
  59. <a href=\"" + DigikeyBomWebPage + "\">Digi-Key's BOM Manager</a>. \
  60. </li> \
  61. <li> \
  62. <b>Mouser Order:</b> This generates a parts list that can be input directly into \
  63. <a href=\"http://www.mouser.com/tools/tools.aspx\">Mouser's BOM import tool</a>. \
  64. </li> \
  65. <li> \
  66. <b>Part Kit Labels:</b> This generates a list of labels that can be applied \
  67. to parts before they are shipped to an assembly house. (This is XESS-specific.) \
  68. </li> \
  69. </ul> \
  70. <h2><a name=\"Output_Formats\">Output Formats</a></h2> \
  71. <p> \
  72. You have the following output formats available when you view or save a BOM: \
  73. <ul> \
  74. <li> \
  75. <b>Text:</b> Straight ASCII text with no formatting. \
  76. </li> \
  77. <li> \
  78. <b>HTML:</b> HTML-encoded text for inclusion in documents. \
  79. </li> \
  80. <li> \
  81. <b>CSV:</b> Comma-separated-values for importing into spreadsheets. \
  82. </li> \
  83. </ul> \
  84. <h2>Actions</h2> \
  85. <p> \
  86. The buttons along the bottom of the dialog box perform the following actions: \
  87. <ul> \
  88. <li> \
  89. <b>View:</b> Opens a window where you can view the BOM in a format determined by the <a href=\"#List_Types\">List Type</a> \
  90. and <a href=\"#Output_Formats\">Output Format</a> radio buttons. \
  91. </li> \
  92. <li> \
  93. <b>Save...:</b> Opens a dialog where you can specify a file to store the BOM. \
  94. </li> \
  95. <li> \
  96. <b>Prices:</b> Fetches and displays quantity-based component pricing from Digi-Key. \
  97. </li> \
  98. <li> \
  99. <b>Order:</b> Opens the appropriate order-entry page and displays the BOM in the required import format. \
  100. </li> \
  101. <li> \
  102. <b>Edit:</b> Opens a dialog where you can edit information from a database you have loaded. \
  103. </li> \
  104. <li> \
  105. <b>Help:</b> Brings up this help screen. \
  106. </li> \
  107. <li> \
  108. <b>Close:</b> Terminates the BOM tool. \
  109. </li> \
  110. </ul> \
  111. <h2>Common BOM Operations</h2> \
  112. <h3>Preparing the Schematic</h3> \
  113. You will need to add the following attributes to the parts in your schematic if you want to use the real-time pricing \
  114. or online ordering features: \
  115. <ul> \
  116. <li> \
  117. <b>MANF:</b> This attribute holds the name of the manufacturer for the part. \
  118. </li> \
  119. <li> \
  120. <b>MANF#:</b> This attribute holds the manufacturer's part number. \
  121. </li> \
  122. <li> \
  123. <b>DIGIKEY#:</b> This attribute holds the Digi-Key part number. \
  124. </li> \
  125. <li> \
  126. <b>MOUSER#:</b> This attribute holds the Mouser part number. \
  127. </li> \
  128. </ul> \
  129. <p> \
  130. The bad news is you have to lookup and enter these attributes for all the parts in your schematic \
  131. that you want included in the real-time pricing and/or the online ordering. \
  132. To assist with this chore, use the <b>attrib-copy</b> ULP to copy the attributes from a single part \
  133. across all identical parts. \
  134. <p> \
  135. To save effort, you can also add these attributes directly to the parts in the library. \
  136. But this won't work if it's a generic part like a resistor whose resistance value will affect it's part number. \
  137. It also won't work for ICs that have multiple package options (for example, SOIC and TSSOP) \
  138. since those also affect the part number. \
  139. <p> \
  140. The good news is you don't need to enter all these attributes for every part to use the ordering/pricing features. \
  141. For example, parts without a Mouser part number simply aren't included in a Mouser order list. \
  142. <h3>Viewing the BOM</h3> \
  143. <p> \
  144. Click on the <b>Vie<u>w</u></b> button to get a preview of the BOM output. \
  145. Use the <a href=\"#List_Types\">List Type</a> \
  146. and <a href=\"#Output_Formats\">Output Format</a> radio buttons to change how the BOM is displayed. \
  147. <h3>Saving the BOM</h3> \
  148. <p> \
  149. Click on the <b><u>S</u>ave</b> button to save the BOM to a file. \
  150. Use the <a href=\"#List_Types\">List Type</a> \
  151. and <a href=\"#Output_Formats\">Output Format</a> radio buttons to select the format and type of data to store. \
  152. <h3>Pricing the BOM</h3> \
  153. <p> \
  154. Click on the <b>Price</b> button to get current pricing information from Digi-Key. \
  155. Pricing will be adjusted based on the quantity you have entered in the <a href=\"#Build_Quantity\">Build Quantity</a> field. \
  156. (Pricing from Mouser is not currently supported.) \
  157. <h3>Ordering Parts</h3> \
  158. <p> \
  159. To order parts for your design from Digi-Key or Mouser, select either the \
  160. <b>Digikey Order</b> or <b>Mouser Order</b> radio button in the <b>List Type</b> box and \
  161. then click on the <b>Order</b> button. \
  162. This will open the appropriate order-entry web page in your default browser and \
  163. display a dialog window with your BOM in the correct import format. \
  164. (You will have to register and login to each site before you can reach the order-entry page.) \
  165. Select the parts list in the <b>Parts Order</b> window. \
  166. Then right-click on the selection and pick <b>Copy</b> from the pop-up menu that appears. \
  167. Go to the order-entry field in your browser and paste the parts list. \
  168. Then proceed to complete the order on the particular site you've chosen. \
  169. <h3>Database Operations</h3> \
  170. <p> \
  171. You can pull in additional information about the used parts by loading \
  172. a database file with the <b><u>L</u>oad</b> button. \
  173. <p> \
  174. A database file must consist of lines of text, each of which contains \
  175. one record consisting of CSV (<u>C</u>omma <u>S</u>eparated <u>V</u>alues) \
  176. or TSV (<u>T</u>ab <u>S</u>eparated <u>V</u>alues) data. \
  177. The very first line must contain a \"header\", which defines a unique name for \
  178. each column, and the first column of every following line must contain \
  179. a unique (non-empty) key for this record. \
  180. <p> \
  181. An example for a valid database file would be: \
  182. <pre> \
  183. Key Manufacturer Order Code Price \
  184. 74LS00N Texas Instruments 123-456 0.20 \
  185. R-EU_0204/5:4k7 Somebody RES4k7 0.10 \
  186. </pre> \
  187. Note that the columns are separated by a <b>tab</b> character (you may also \
  188. use a semicolon (';') to separate the columns, but then you will have to make sure \
  189. none of the data items contains a semicolon). \
  190. The keys for looking up records in the database are built from the \
  191. parts' values. If a part's device has defined \"value on\" it means that \
  192. the user needs to specify a particular value for this part, as for \
  193. example with a resistor. In such a case the key consists of the device \
  194. name and the user defined value, separated by a colon (':'). If the \
  195. device has \"value off\", only the device name is used as key (if the \
  196. user has edited the value of such a part and insisted on changing \
  197. it, the edited value will be used). \
  198. <h4>Creating a new database</h4> \
  199. <p> \
  200. Click on the <b><u>N</u>ew</b> button to create a new database. \
  201. You will get a dialog in which you can define the names of the column headers \
  202. for your new database. The first column always contains the key for database \
  203. lookups and can't be deleted (you can edit it, though, to give it a different \
  204. name than the default \"Key\"). This first column will not be visible in the \
  205. generated list, so you don't really need to worry about it. \
  206. <h4>Editing the database</h4> \
  207. <p> \
  208. If you have loaded a database you can either double click on a line \
  209. in the list, or select a line and press Enter (or click on the <b>Edit</b> \
  210. button) to bring up a dialog in which you can edit the database entry \
  211. for this part. If the database has been modified you will be asked if \
  212. you want to save it before leaving the program or loading a new database. \
  213. <h1>Authors</h1> \
  214. <p> \
  215. Original Author: <a href=\"mailto:support@cadsoft.de?subject=bom-xs ULP\">support@cadsoft.de</a> \
  216. <p> \
  217. Modified by: Dave Vandenbout / XESS Corp. - <a href=\"mailto:devb@xess.com?subject=bom-xs ULP\">devb@xess.com</a> \
  218. ";
  219.  
  220. if (!schematic) {
  221. dlgMessageBox(usage + "<hr><b>ERROR: No schematic!</b><p>\nThis program can only work in the schematic editor.");
  222. exit(1);
  223. }
  224.  
  225. //XXX
  226. /*
  227. TODO: - Query user for missing database entries ("Check" button)
  228. - Allow user to define which database columns to actually use
  229. - dto. for the internal data?
  230. - store and retrieve the setup?
  231. - what if this is run in a board?
  232. */
  233.  
  234. int BuildQty = 1;
  235. int NumParts;
  236. numeric string Lines[];
  237. numeric string PartName[], PartValue[], PartPrefix[], PartDevice[], PartPackage[], PartHeadline[], PartDescription[],
  238. PartManf[], PartManfNumber[], PartMouserNumber[], PartDigikeyNumber[], PartMouserPrice[], PartDigikeyPrice[];
  239. int PartValueOn[];
  240. int Selected;
  241.  
  242. real TotalDigikeyPrice = -1.0;
  243. real UnitDigikeyPrice = -1.0;
  244.  
  245. enum { ltParts, ltValues, ltManf, ltManfDisti, ltDigikey, ltMouser, ltLabels }; // List Types
  246. enum { ofText, ofHTML, ofCSV }; // Output Formats
  247. int ListType = 0;
  248. int OutputFormat = 0;
  249.  
  250. int disableHeader = 0;
  251.  
  252. string DatabaseFile;
  253. string Database[];
  254. char DatabaseSeparator = '\t';
  255. string DatabaseFields[];
  256. int DatabaseModified = 0;
  257.  
  258. int PartSheet[];
  259. string PartNum[];
  260. string PartNumPrev[];
  261.  
  262. string PartVal[];
  263. string PartValSave[];
  264. string PartDevChange[];
  265. string PartDev[];
  266.  
  267. string strPartNumAttrName;
  268.  
  269. char ValueSeparator = ':';
  270.  
  271. string StripWhiteSpace(string s)
  272. {
  273. while (s && isspace(s[0]))
  274. s = strsub(s, 1);
  275. while (s && isspace(s[strlen(s) - 1]))
  276. s = strsub(s, 0, strlen(s) - 1);
  277. return s;
  278. }
  279.  
  280. void CollectPartData(void)
  281. {
  282. NumParts = 0;
  283.  
  284. schematic(SCH) {
  285. SCH.parts(P) {
  286. if (P.device.package) {
  287.  
  288. if( P.attribute["PARTNO"] != "NONE" )
  289. if( P.value != "dnp" ) {
  290.  
  291. PartName[NumParts] = P.name;
  292. PartValue[NumParts] = P.value;
  293. PartPrefix[NumParts] = P.device.prefix;
  294. PartDevice[NumParts] = P.device.name;
  295. PartPackage[NumParts] = P.device.package.name;
  296. PartHeadline[NumParts] = P.device.headline;
  297. PartDescription[NumParts] = P.device.description;
  298. PartValueOn[NumParts] = P.device.value == "On";
  299. PartManf[NumParts] = P.attribute["MANF"];
  300. PartManfNumber[NumParts] = P.attribute["PARTNO"];
  301. PartMouserNumber[NumParts] = P.attribute["MOUSER"];
  302. PartDigikeyNumber[NumParts] = P.attribute["DIGIKEY"];
  303.  
  304. NumParts++;
  305. }
  306. }
  307. }
  308. }
  309. }
  310.  
  311.  
  312. void UpdatePartData(void)
  313. {
  314. NumParts = 0;
  315.  
  316. schematic(SCH) {
  317. SCH.parts(P) {
  318. if (P.device.package) {
  319. /*
  320. P.name = PartName[NumParts];
  321. P.value = PartValue[NumParts] ;
  322. P.device.prefix = PartPrefix[NumParts] ;
  323. P.device.name = PartDevice[NumParts] ;
  324. P.device.package.name = PartPackage[NumParts] ;
  325. P.device.headline = PartHeadline[NumParts] ;
  326. P.device.description = PartDescription[NumParts];
  327. P.attribute["MANF"] = PartManf[NumParts];
  328. P.attribute["PARTNO"] = PartManfNumber[NumParts];
  329. P.attribute["MOUSER"] = PartMouserNumber[NumParts];
  330. P.attribute["DIGIKEY"] = PartDigikeyNumber[NumParts];
  331. */
  332.  
  333. NumParts++;
  334. }
  335. }
  336. }
  337. }
  338.  
  339.  
  340.  
  341. string DatabaseHeader(void)
  342. {
  343. string s;
  344.  
  345. if (Database[0]) {
  346. string a[];
  347. int n = strsplit(a, Database[0], DatabaseSeparator);
  348. int i;
  349. for (i = 1; i < n; i++) {
  350. s += "\t" + a[i];
  351. DatabaseFields[i - 1] = a[i];
  352. }
  353. DatabaseFields[i - 1] = "";
  354. }
  355. return s;
  356. }
  357.  
  358. string DatabaseKey(int i)
  359. {
  360. string key = PartValue[i];
  361. if (PartValueOn[i])
  362. key = PartDevice[i] + ValueSeparator + key;
  363. return key;
  364. }
  365.  
  366. string DatabaseLookup(string key, int f)
  367. {
  368. return lookup(Database, key, DatabaseFields[f], DatabaseSeparator);
  369. }
  370.  
  371. void GeneratePartList(void)
  372. {
  373. int NumLines = 0;
  374.  
  375. //XXX column sequence?
  376. Lines[NumLines++] = "Part\tValue\tDevice\tPackage\tManufacturer\tPart#\tDescription\tDigikey" + DatabaseHeader();
  377. for (int i = 0; i < NumParts; i++) {
  378. Lines[NumLines] = PartName[i] + "\t" + PartValue[i] + "\t" + PartDevice[i] + "\t" + PartPackage[i] + "\t" + PartManf[i] + "\t" + PartManfNumber[i] +
  379. "\t" + PartHeadline[i]+ "\t" + PartDigikeyNumber[i];
  380. if (Database[0]) {
  381. string key = DatabaseKey(i);
  382. for (int f = 0; DatabaseFields[f]; f++)
  383. Lines[NumLines] += "\t" + DatabaseLookup(key, f);
  384. Lines[NumLines] += "\t" + key; // hidden field!
  385. }
  386. NumLines++;
  387. }
  388. Lines[NumLines] = "";
  389. }
  390.  
  391. void GenerateValueList(void)
  392. {
  393. int NumLines = 0;
  394. int Index[];
  395.  
  396. //XXX column sequence?
  397. Lines[NumLines++] = "Qty\tValue\tDevice\tParts" + DatabaseHeader();
  398. sort(NumParts, Index, PartValue, PartDevice, PartName);
  399. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; ) {
  400. int i1 = Index[n1];
  401. if (n2 < NumParts) {
  402. int i2 = Index[n2];
  403. //XXX value on/off?
  404. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  405. continue;
  406. }
  407. string Quantity;
  408. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  409. Lines[NumLines] = Quantity + "\t" + PartValue[i1] + "\t" + PartDevice[i1] + "\t";
  410. for (;;) {
  411. Lines[NumLines] += PartName[i1];
  412. if (++n1 < n2) {
  413. i1 = Index[n1];
  414. Lines[NumLines] += ", ";
  415. }
  416. else
  417. break;
  418. }
  419. if (Database[0]) {
  420. string key = DatabaseKey(i1);
  421. for (int f = 0; DatabaseFields[f]; f++)
  422. Lines[NumLines] += "\t" + DatabaseLookup(key, f);
  423. Lines[NumLines] += "\t" + key; // hidden field!
  424. }
  425. NumLines++;
  426. }
  427. Lines[NumLines] = "";
  428. }
  429.  
  430. void GenerateManfList(void)
  431. {
  432. int NumLines = 0;
  433. int Index[];
  434.  
  435. //XXX column sequence?
  436. Lines[NumLines++] = "Qty\tManf#\tManf\tDevice\tValue\tDescription" + DatabaseHeader();
  437. sort(NumParts, Index, PartPrefix, PartValue, PartDevice, PartManf, PartManfNumber, PartHeadline);
  438. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; ) {
  439. int i1 = Index[n1];
  440. if (n2 < NumParts) {
  441. int i2 = Index[n2];
  442. //XXX value on/off?
  443. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  444. continue;
  445. }
  446. string Quantity;
  447. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  448. Lines[NumLines] = Quantity
  449. + "\t" + PartManfNumber[i1]
  450. + "\t" + PartManf[i1]
  451. + "\t" + PartDevice[i1]
  452. + "\t" + PartValue[i1]
  453. + "\t" + PartHeadline[i1];
  454. n1 = n2;
  455. i1 = Index[n2-1];
  456. NumLines++;
  457. }
  458. Lines[NumLines] = "";
  459. }
  460.  
  461. void GenerateManfDistiList(void)
  462. {
  463. int NumLines = 0;
  464. int Index[];
  465. string TotalDigikeyPriceStr;
  466. string UnitDigikeyPriceStr;
  467.  
  468. //XXX column sequence?
  469. Lines[NumLines++] = "Qty\tDigikey#\tDigikey $\tMouser#\tMouser $\tManf#\tManf\tDevice\tValue\tDescription" + DatabaseHeader();
  470. sort(NumParts, Index, PartPrefix, PartValue, PartDevice, PartManf, PartManfNumber, PartHeadline);
  471. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; ) {
  472. int i1 = Index[n1];
  473. if (n2 < NumParts) {
  474. int i2 = Index[n2];
  475. //XXX value on/off?
  476. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  477. continue;
  478. }
  479. string Quantity;
  480. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  481. Lines[NumLines] = Quantity
  482. + "\t" + PartDigikeyNumber[i1]
  483. + "\t" + PartDigikeyPrice[i1]
  484. + "\t" + PartMouserNumber[i1]
  485. + "\t" + PartMouserPrice[i1]
  486. + "\t" + PartManfNumber[i1]
  487. + "\t" + PartManf[i1]
  488. + "\t" + PartDevice[i1]
  489. + "\t" + PartValue[i1]
  490. + "\t" + PartHeadline[i1];
  491. n1 = n2;
  492. i1 = Index[n2-1];
  493. NumLines++;
  494. }
  495. if(TotalDigikeyPrice >= 0.0)
  496. {
  497. sprintf(TotalDigikeyPriceStr,"%11.2f",TotalDigikeyPrice);
  498. sprintf(UnitDigikeyPriceStr,"%11.2f",UnitDigikeyPrice);
  499. Lines[NumLines++] = "\t" + "***Total Price***" + "\t" + TotalDigikeyPriceStr;
  500. Lines[NumLines++] = "\t" + "***Unit Price***" + "\t" + UnitDigikeyPriceStr;
  501. }
  502. Lines[NumLines] = "";
  503. }
  504.  
  505. void GenerateMouserOrderList(void)
  506. {
  507. int NumLines = 0;
  508. int Index[];
  509.  
  510. //XXX column sequence?
  511. Lines[NumLines++] = "Mouser Order List";
  512. sort(NumParts, Index, PartPrefix, PartValue, PartDevice, PartMouserNumber);
  513. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; ) {
  514. int i1 = Index[n1];
  515. if (n2 < NumParts) {
  516. int i2 = Index[n2];
  517. //XXX value on/off?
  518. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  519. continue;
  520. }
  521. if(PartMouserNumber[i1]){
  522. string Quantity;
  523. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  524. Lines[NumLines] = PartMouserNumber[i1] + "|" + Quantity;
  525. NumLines++;
  526. }
  527. n1 = n2;
  528. i1 = Index[n2-1];
  529. }
  530. Lines[NumLines] = "";
  531. }
  532.  
  533. void GenerateDigikeyOrderList(void)
  534. {
  535. int NumLines = 0;
  536. int Index[];
  537.  
  538. //XXX column sequence?
  539. Lines[NumLines++] = "Digikey Order List";
  540. sort(NumParts, Index, PartPrefix, PartValue, PartDevice, PartDigikeyNumber);
  541. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; )
  542. {
  543. int i1 = Index[n1];
  544. if (n2 < NumParts)
  545. {
  546. int i2 = Index[n2];
  547. //XXX value on/off?
  548. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  549. continue;
  550. }
  551. if(PartDigikeyNumber[i1])
  552. {
  553. string Quantity;
  554. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  555. Lines[NumLines] = Quantity + "," + PartDigikeyNumber[i1];
  556. NumLines++;
  557. }
  558. n1 = n2;
  559. i1 = Index[n2-1];
  560. }
  561. Lines[NumLines] = "";
  562. }
  563.  
  564. void GenerateLabels(void)
  565. {
  566. numeric string TempLines[];
  567. int NumLines = 0;
  568. int Index[];
  569.  
  570. //XXX column sequence?
  571. sort(NumParts, Index, PartPrefix, PartValue, PartName, PartDevice);
  572. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; )
  573. {
  574. int i1 = Index[n1];
  575. if (n2 < NumParts)
  576. {
  577. int i2 = Index[n2];
  578. //XXX value on/off?
  579. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])
  580. continue;
  581. }
  582. if(PartManfNumber[i1])
  583. {
  584. string Quantity;
  585. sprintf(Quantity, "%d", (n2 - n1) * BuildQty);
  586. string date = t2string(time(),"MM/dd/yyyy");
  587. string Desc = "";
  588. sprintf(Desc,"%s %s %s", PartValue[i1], PartPackage[i1], PartHeadline[i1]);
  589.  
  590. TempLines[NumLines] = "";
  591. for (;;)
  592. {
  593. TempLines[NumLines] += PartName[i1];
  594. if (++n1 < n2)
  595. {
  596. i1 = Index[n1];
  597. TempLines[NumLines] += " ";
  598. }
  599. else
  600. break;
  601. }
  602. TempLines[NumLines] += " \\\\" + PartManfNumber[i1] + " \\\\" + Desc + " \\\\Qty: " + Quantity + " \\\\Pckg: 0 \\\\XESS Corp. " + date + " |" ;
  603. NumLines++;
  604. }
  605. n1 = n2;
  606. i1 = Index[n2-1];
  607. }
  608.  
  609. sort(NumLines, Index, TempLines);
  610. for(int i=0; i<NumLines; i++)
  611. {
  612. Lines[i+1] = TempLines[Index[i]];
  613. }
  614. Lines[0] = "Part Kit Labels";
  615. NumLines++;
  616. Lines[NumLines] = "";
  617. }
  618.  
  619. void GenerateList(void)
  620. {
  621. switch (ListType) {
  622. case ltParts: GeneratePartList(); break;
  623. case ltValues: GenerateValueList(); break;
  624. case ltManf: GenerateManfList(); break;
  625. case ltManfDisti: GenerateManfDistiList(); break;
  626. case ltMouser: GenerateMouserOrderList(); break;
  627. case ltDigikey: GenerateDigikeyOrderList(); break;
  628. case ltLabels: GenerateLabels(); break;
  629. }
  630. }
  631.  
  632. string MakeListHeader(void)
  633. {
  634. string s;
  635. schematic(SCH) sprintf(s, "Partlist exported from %s at %s", SCH.name, t2string(time()));
  636. return s;
  637. }
  638.  
  639. string MakeListText(void)
  640. {
  641. int l, Width[];
  642. for (l = 0; Lines[l]; l++) {
  643. string a[];
  644. for (int n = strsplit(a, Lines[l], '\t'); n--; )
  645. Width[n] = max(Width[n], strlen(a[n]));
  646. }
  647. string List;
  648. if(!disableHeader) {
  649. List = MakeListHeader() + "\n\n";
  650. }
  651. int numHeaders;
  652. for (l = 1; Lines[l]; l++) {
  653. List += Lines[l] + "\n";
  654. }
  655. return List;
  656. }
  657.  
  658. string MakeListHTML(void)
  659. {
  660. string List;
  661. if(!disableHeader) {
  662. List = "<b>" + MakeListHeader() + "</b>\n<p>\n";
  663. }
  664. List += "<table>\n";
  665. int numHeaders;
  666. for (int l = 0; Lines[l]; l++) {
  667. List += "<tr>";
  668. string a[];
  669. int n = strsplit(a, Lines[l], '\t');
  670. if (l == 0)
  671. numHeaders = n;
  672. else
  673. n = numHeaders; // for the hidden key!
  674. for (int i = 0; i < n; i++) {
  675. if (l == 0)
  676. a[i] = "<b>" + a[i] + "</b>";
  677. List += "<td>" + a[i] + "</td>";
  678. }
  679. List += "</tr>\n";
  680. }
  681. List += "</table>\n";
  682. return List;
  683. }
  684.  
  685. string MakeListCSV(void)
  686. {
  687. string List;
  688. if(!disableHeader) {
  689. List = MakeListHeader();
  690. }
  691. int numHeaders;
  692. for (int l = 0; Lines[l]; l++) {
  693. string a[];
  694. int n = strsplit(a, Lines[l], '\t');
  695. if (l == 0)
  696. numHeaders = n;
  697. else
  698. n = numHeaders; // for the hidden key!
  699. for (int i = 0; i < n; i++) {
  700. List += a[i] + ",";
  701. }
  702. List += "\n";
  703. }
  704. return List;
  705. }
  706.  
  707. string MakeList(void)
  708. {
  709. switch (OutputFormat) {
  710. case ofText: return MakeListText(); break;
  711. case ofHTML: return MakeListHTML(); break;
  712. case ofCSV: return MakeListCSV(); break;
  713. }
  714. return "";
  715. }
  716.  
  717. void ViewList(string title)
  718. {
  719. dlgDialog(title) {
  720. string s = MakeList();
  721. if (OutputFormat != ofHTML)
  722. s = "<pre>" + s + "</pre>";
  723. dlgHBoxLayout dlgSpacing(400);
  724. dlgHBoxLayout {
  725. dlgVBoxLayout dlgSpacing(300);
  726. dlgTextView(s);
  727. }
  728. dlgHBoxLayout {
  729. dlgStretch(1);
  730. dlgPushButton("-Close") dlgReject();
  731. }
  732. };
  733. }
  734.  
  735. void SaveList(void)
  736. {
  737. string FileName;
  738. schematic(SCH) FileName = filesetext(SCH.name, OutputFormat == ofHTML ? ".htm" : (OutputFormat == ofCSV ? ".csv" : ".bom"));
  739. FileName = dlgFileSave("Save Bill Of Material", FileName);
  740. if (FileName) {
  741. string a[];
  742. if (!fileglob(a, FileName) || dlgMessageBox("File '" + FileName + "' exists\n\nOverwrite?", "+&Yes", "-&No") == 0) {
  743. output(FileName, "wt") {
  744. printf("%s", MakeListHeader()); // Only put header in when list is saved to file.
  745. printf("%s", MakeList()); // using "%s" to avoid problems if list contains any '%'
  746. }
  747. }
  748. }
  749. }
  750.  
  751.  
  752. //===================================================================================================
  753.  
  754. real Number[];
  755.  
  756. int ExtractNumbers(string Line)
  757. {
  758. int NumNumbers = 0;
  759. string NumberText = "";
  760. for(int i=0; i<strlen(Line); i++)
  761. {
  762. if(isdigit(Line[i]) || (Line[i]=='.') || (Line[i]==','))
  763. {
  764. if(Line[i] != ',')
  765. NumberText += Line[i];
  766. }
  767. else if(strlen(NumberText)!=0)
  768. {
  769. Number[NumNumbers++] = strtod(NumberText);
  770. NumberText = "";
  771. }
  772. }
  773. return NumNumbers;
  774. }
  775.  
  776. string GetDigikeyPrice(string PartNumber, int Quantity)
  777. {
  778. string Html;
  779. string htmlRedirect;
  780.  
  781. if(PartNumber == "")
  782. return "";
  783.  
  784. if(netget(Html,"http://search.digikey.com/scripts/DkSearch/dksus.dll?Detail&name="+PartNumber,40) >= 0)
  785. {
  786. int redirectPos = strstr(Html,"http://www.digikey.com/product-detail/");
  787.  
  788. if(redirectPos >= 0) {
  789.  
  790. htmlRedirect = strsub(Html, redirectPos);
  791. if(netget(Html,htmlRedirect,40) < 0) {
  792. return "A???";
  793. }
  794.  
  795. }
  796.  
  797. int StartPos = strstr(Html,"Extended Price");
  798. if(StartPos < 0)
  799. return "A???";
  800. Html = strsub(Html, StartPos+strlen("Extended Price"));
  801. int EndPos = strstr(Html,"</table>");
  802. if(EndPos < 0)
  803. return "B???";
  804. Html = strsub(Html,0,EndPos);
  805. string Line[];
  806. int NumLines = strsplit(Line,Html,'\n');
  807. string Price = "";
  808. for(int i=0; i<NumLines; i++)
  809. {
  810. int NumNumbers = ExtractNumbers(Line[i]);
  811. switch(NumNumbers)
  812. {
  813. case 2:
  814. if(Quantity >= Number[0])
  815. sprintf(Price,"%11.2f",Number[1]/Number[0]);
  816. else
  817. {
  818. if (Price == "")
  819. sprintf(Price,"%11.2f",Number[1]/Number[0]);
  820. return Price;
  821. }
  822. break;
  823. case 3:
  824. if(Quantity >= Number[0])
  825. sprintf(Price,"%11.2f",Number[1]);
  826. else
  827. {
  828. if (Price == "")
  829. sprintf(Price,"%11.2f",Number[1]);
  830. return Price;
  831. }
  832. break;
  833. default:
  834. break;
  835. }
  836. }
  837. return Price;
  838. }
  839. return "C???";
  840. }
  841.  
  842. void GetPartPrices(void)
  843. {
  844. int Index[];
  845.  
  846. TotalDigikeyPrice = 0.0;
  847. sort(NumParts, Index, PartPrefix, PartValue, PartDevice, PartManf, PartManfNumber);
  848. for (int n1 = 0, n2 = 0; ++n2 <= NumParts; ) {
  849. int i1 = Index[n1];
  850. if (n2 < NumParts) {
  851. int i2 = Index[n2];
  852. if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2])//XXX && lname[i1] == lname[i2])
  853. continue;
  854. }
  855. int Quantity = (n2 - n1) * BuildQty;
  856. PartDigikeyPrice[i1] = GetDigikeyPrice(PartDigikeyNumber[i1],Quantity);
  857. TotalDigikeyPrice += strtod(PartDigikeyPrice[i1]) * Quantity;
  858. n1 = n2;
  859. i1 = Index[n2-1];
  860. }
  861. UnitDigikeyPrice = TotalDigikeyPrice / BuildQty;
  862. GenerateManfDistiList();
  863. }
  864.  
  865. void PlaceOrder(void)
  866. {
  867. int saveOutputFormat = OutputFormat;
  868. OutputFormat = ofText;
  869. disableHeader = 1;
  870. switch (ListType) {
  871. case ltMouser:
  872. system("rundll32 url.dll,FileProtocolHandler " + MouserBomWebPage);
  873. GenerateMouserOrderList();
  874. ViewList("Mouser Parts Order");
  875. break;
  876. case ltDigikey:
  877. system("rundll32 url.dll,FileProtocolHandler " + DigikeyBomWebPage);
  878. GenerateDigikeyOrderList();
  879. ViewList("Digi-Key Parts Order");
  880. break;
  881. default:
  882. dlgMessageBox("You must select either 'DigiKey Order' or 'Mouser Order' in the List Type box.");
  883. break;
  884. }
  885. disableHeader = 0;
  886. OutputFormat = saveOutputFormat;
  887. }
  888.  
  889. //===================================================================================================
  890.  
  891.  
  892. int ReadDatabase(string FileName)
  893. {
  894. string data;
  895. if (fileread(data, FileName) > 0) {
  896. strsplit(Database, data, '\n');
  897. DatabaseSeparator = (strchr(Database[0], '\t') > -1) ? '\t' : ';';
  898. DatabaseFile = FileName;
  899. return 1;
  900. }
  901. return 0;
  902. }
  903.  
  904. // --- Create a new database -------------------------------------------------
  905.  
  906. string Headers[];
  907. int NumHeaders;
  908. int SelectedHeader;
  909.  
  910. int NewDatabaseHeaderOk(string Name)
  911. {
  912. for (int i = 0; i < NumHeaders; i++) {
  913. if (Name == Headers[i]) {
  914. dlgMessageBox("Name already defined!");
  915. return 0;
  916. }
  917. }
  918. return 1;
  919. }
  920.  
  921. void NewDatabaseEdit(string Title, string Name)
  922. {
  923. int NewName = !Name;
  924. dlgDialog(Title + " Header") {
  925. dlgLabel("&Name:");
  926. dlgStringEdit(Name);
  927. dlgHBoxLayout {
  928. dlgStretch(1);
  929. dlgPushButton("+Ok") {
  930. Name = StripWhiteSpace(Name);
  931. if (!NewName) {
  932. if (Name == Headers[SelectedHeader] || NewDatabaseHeaderOk(Name)) {
  933. Headers[SelectedHeader] = Name;
  934. dlgAccept();
  935. }
  936. }
  937. else if (Name) {
  938. if (NewDatabaseHeaderOk(Name)) {
  939. SelectedHeader = NumHeaders;
  940. Headers[NumHeaders] = Name;
  941. Headers[++NumHeaders] = "";
  942. dlgAccept();
  943. }
  944. }
  945. else
  946. dlgMessageBox("Name can't be empty!");
  947. }
  948. dlgPushButton("-Cancel") dlgReject();
  949. }
  950. };
  951. }
  952.  
  953. void NewDatabase(void)
  954. {
  955. DatabaseFile = "";
  956. Database[0] = "";
  957. GenerateList();
  958. dlgRedisplay();
  959.  
  960. Headers[0] = "Key";
  961. Headers[1] = "";
  962. NumHeaders = 1;
  963. SelectedHeader = -1;
  964. int result = dlgDialog("New Database") {
  965. dlgHBoxLayout {
  966. dlgVBoxLayout {
  967. dlgLabel("&Headers");
  968. dlgListBox(Headers, SelectedHeader) NewDatabaseEdit("Edit", Headers[SelectedHeader]);
  969. }
  970. dlgVBoxLayout {
  971. dlgPushButton("&Add") NewDatabaseEdit("New", "");
  972. dlgPushButton("&Del") {
  973. if (SelectedHeader > 0) {
  974. for (int i = SelectedHeader; i < NumHeaders - 1; i++)
  975. Headers[i] = Headers[i + 1];
  976. Headers[--NumHeaders] = "";
  977. if (SelectedHeader >= NumHeaders)
  978. SelectedHeader = NumHeaders - 1;
  979. }
  980. else
  981. dlgMessageBox("Can't delete the \"Key\" header!\n\nUse \"Edit\" to change it.");
  982. }
  983. dlgPushButton("&Edit") {
  984. if( SelectedHeader != -1 )
  985. NewDatabaseEdit("Edit", Headers[SelectedHeader]);
  986. }
  987. }
  988. }
  989. dlgHBoxLayout {
  990. dlgStretch(1);
  991. dlgPushButton("+Ok") {
  992. if (NumHeaders > 1)
  993. dlgAccept();
  994. else
  995. dlgMessageBox("Please add at least one header!");
  996. }
  997. dlgPushButton("-Cancel") dlgReject();
  998. }
  999. };
  1000. if (result) {
  1001. string sep;
  1002. for (int i = 0; Headers[i]; i++) {
  1003. Database[0] += sep + Headers[i];
  1004. sep = "\t";
  1005. }
  1006. DatabaseSeparator = '\t';
  1007. DatabaseModified = 1;
  1008. GenerateList();
  1009. }
  1010. }
  1011.  
  1012. // ---
  1013.  
  1014. void LoadDatabase(void)
  1015. {
  1016. string FileName = dlgFileOpen("Choose database file", DatabaseFile, "Database files (*.tsv *.csv);;All files (*)");
  1017. if (FileName) {
  1018. if (ReadDatabase(FileName)) {
  1019. GenerateList();
  1020. DatabaseModified = 0;
  1021. }
  1022. }
  1023. }
  1024.  
  1025. int SaveDatabase(void)
  1026. {
  1027. if (!DatabaseFile) {
  1028. string ext = (DatabaseSeparator == '\t') ? ".tsv" : ".csv";
  1029. DatabaseFile = dlgFileSave("Save database file", "", "Database files (*" + ext + ");;All files (*)");
  1030. if (!DatabaseFile)
  1031. return 0;
  1032. if (fileext(DatabaseFile) != ext)
  1033. DatabaseFile += ext;
  1034. }
  1035. fileerror();
  1036. output(DatabaseFile, "wt") {
  1037. for (int i = 0; Database[i]; i++)
  1038. printf("%s\n", Database[i]);
  1039. };
  1040. return !fileerror();
  1041. }
  1042.  
  1043. void EditDatabaseEntry(string Key, int Entry)
  1044. {
  1045. string Header[];
  1046. string Data[];
  1047. int Fields = strsplit(Header, Database[0], DatabaseSeparator);
  1048. strsplit(Data, Database[Entry], DatabaseSeparator);
  1049. if (!Data[0])
  1050. Data[0] = Key;
  1051. int result = dlgDialog("Edit Database") {
  1052. dlgGridLayout {
  1053. for (int f = 0; f < Fields; f++) {
  1054. dlgCell(f, 0) dlgLabel(Header[f]);
  1055. dlgCell(f, 1) if (f) { dlgStringEdit(Data[f]); } else { dlgLabel(Data[f]); }
  1056. }
  1057. }
  1058. dlgHBoxLayout {
  1059. dlgStretch(1);
  1060. dlgPushButton("+Ok") dlgAccept();
  1061. dlgPushButton("-Cancel") dlgReject();
  1062. }
  1063. };
  1064. if (result) {
  1065. for (int f = 0; f < Fields; f++)
  1066. Data[f] = StripWhiteSpace(Data[f]);
  1067. Database[Entry] = strjoin(Data, DatabaseSeparator);
  1068. DatabaseModified = 1;
  1069. GenerateList();
  1070. }
  1071. }
  1072.  
  1073. void EditDatabase(void)
  1074. {
  1075. if (Database[0]) {
  1076. if (Selected) {
  1077. string a[];
  1078. int KeyField = strsplit(a, Lines[0], '\t');
  1079. strsplit(a, Lines[Selected], '\t');
  1080. string key = a[KeyField];
  1081. string data;
  1082. int entry;
  1083. for (entry = 0; Database[entry]; entry++) {
  1084. strsplit(a, Database[entry], DatabaseSeparator);
  1085. if (a[0] == key) {
  1086. data = Database[entry];
  1087. break;
  1088. }
  1089. }
  1090. EditDatabaseEntry(key, entry);
  1091. }
  1092. else
  1093. dlgMessageBox("Please select a list entry first!");
  1094. }
  1095. else
  1096. dlgMessageBox("Please load a database file first!");
  1097. }
  1098.  
  1099. int NewDigikeyEdit(string Title, int index)
  1100. {
  1101. string name;
  1102. name = PartDigikeyNumber[ index ];
  1103. dlgDialog(Title + " Header") {
  1104. dlgLabel("&Part:");
  1105. dlgStringEdit(name);
  1106. dlgHBoxLayout {
  1107. dlgStretch(1);
  1108. dlgPushButton("+Ok") {
  1109. dlgAccept();
  1110. PartDigikeyNumber[ index ] = name;
  1111. return 1;
  1112. }
  1113. dlgPushButton("-Cancel") dlgReject();
  1114. }
  1115. };
  1116. return 0;
  1117. }
  1118.  
  1119. void AddDigikey()
  1120. {
  1121. if (Selected) {
  1122.  
  1123. if( NewDigikeyEdit("Digikey Part Number",Selected-1)) {
  1124. UpdatePartData();
  1125. GenerateList();
  1126. }
  1127. }
  1128. else
  1129. dlgMessageBox("Please select a list entry first!");
  1130. }
  1131.  
  1132. int OkToClose(void)
  1133. {
  1134. if (DatabaseModified) {
  1135. switch (dlgMessageBox("Database has been modified\n\nSave?", "+&Yes", "&No", "-Cancel")) {
  1136. case 0: return SaveDatabase();
  1137. case 1: break;
  1138. case 2: return 0;
  1139. }
  1140. }
  1141. return 1;
  1142. }
  1143.  
  1144. void DisplayHelp(void)
  1145. {
  1146. dlgDialog("Bill Of Material - Help") {
  1147. dlgHBoxLayout dlgSpacing(400);
  1148. dlgHBoxLayout {
  1149. dlgVBoxLayout dlgSpacing(300);
  1150. dlgTextView(HelpText);
  1151. }
  1152. dlgHBoxLayout {
  1153. dlgStretch(1);
  1154. dlgPushButton("-Close") dlgReject();
  1155. }
  1156. };
  1157. }
  1158.  
  1159. CollectPartData();
  1160. GenerateList();
  1161.  
  1162. dlgDialog("Bill Of Material - v" + Version) {
  1163. dlgListView("", Lines, Selected) EditDatabase();
  1164. dlgHBoxLayout {
  1165. dlgLabel("Database:");
  1166. dlgLabel(DatabaseFile, 1);
  1167. dlgPushButton("&Load") if (OkToClose()) LoadDatabase();
  1168. dlgPushButton("&New") if (OkToClose()) NewDatabase();
  1169. dlgStretch(1);
  1170. }
  1171. dlgHBoxLayout {
  1172. dlgLabel("Build Quantity:");
  1173. dlgIntEdit(BuildQty,1,100000000);
  1174. dlgStretch(50);
  1175. }
  1176. dlgHBoxLayout {
  1177. dlgGroup("List Type") {
  1178. dlgRadioButton("&Parts", ListType) GeneratePartList();
  1179. dlgRadioButton("&Values", ListType) GenerateValueList();
  1180. dlgRadioButton("&Manf", ListType) GenerateManfList();
  1181. dlgRadioButton("Manf+Distributors", ListType) GenerateManfDistiList();
  1182. dlgRadioButton("Digikey Order", ListType) GenerateDigikeyOrderList();
  1183. dlgRadioButton("Mouser Order", ListType) GenerateMouserOrderList();
  1184. dlgRadioButton("Part Kit Labels", ListType) GenerateLabels();
  1185. }
  1186. dlgGroup("Output Format") {
  1187. dlgRadioButton("&Text", OutputFormat);
  1188. dlgRadioButton("&HTML", OutputFormat);
  1189. dlgRadioButton("&CSV", OutputFormat);
  1190. }
  1191. dlgStretch(50);
  1192. }
  1193. dlgHBoxLayout {
  1194. dlgPushButton("Vie&w") ViewList("BOM Preview");
  1195. dlgPushButton("&Save...") SaveList();
  1196. dlgPushButton("Prices") GetPartPrices();
  1197. dlgPushButton("Order") PlaceOrder();
  1198. dlgPushButton("+Edit") EditDatabase();
  1199. dlgPushButton("+Assign DK") AddDigikey();
  1200. dlgPushButton("&Help") DisplayHelp();
  1201. dlgPushButton("-Close") if (OkToClose()) dlgAccept();
  1202. dlgStretch(1);
  1203. }
  1204. };
  1205.  
  1206.  
  1207. // From box-ex.ulp
  1208.  
  1209. int ApplyAllAttrs = 0;
  1210. int PartNumModified = 0;
  1211.  
  1212. int WriteScriptData(string fileName)
  1213. {
  1214. if (!fileName)
  1215. if (fileext(fileName) != ".scr")
  1216. fileName += ".scr";
  1217.  
  1218. fileerror();
  1219.  
  1220. int nsheet = -1;
  1221.  
  1222. output(fileName, "wt")
  1223. {
  1224. printf("#\n# generated by BOM-XS v%s\n#\n", Version );
  1225. printf("SET UNDO_LOG OFF;\n");
  1226. printf("CHANGE DISPLAY OFF;\n");
  1227.  
  1228. for (int i=0; i < NumParts;i++)
  1229. {
  1230. // Is the part we're changing on the current sheet?
  1231. // If not, move the current sheet with this part.
  1232.  
  1233. if (nsheet != PartSheet[i])
  1234. {
  1235. printf("EDIT .s%d;\n", PartSheet[i]);
  1236. nsheet = PartSheet[i];
  1237. }
  1238.  
  1239. // Do we have any part number changes on this sheet?
  1240. // If so, set the new part number attribute.
  1241.  
  1242. if (ApplyAllAttrs || ((PartNum[i] != "") && (PartNum[i] != PartNumPrev[i])))
  1243. {
  1244. // Now add the updated part number attribute back.
  1245. printf("ATTRIBUTE '%s' '%s' '%s';\n",
  1246. PartName[i], strPartNumAttrName, PartNum[i]);
  1247. }
  1248.  
  1249. // If the user has assigned a new part value different from
  1250. // what was originally loaded, we need to apply the value
  1251. // change to the part also.
  1252.  
  1253. if (PartVal[i] != PartValSave[i])
  1254. printf("VALUE %s '%s';\n", PartName[i], PartVal[i]);
  1255.  
  1256. // If the user has assigned a new package name different from
  1257. // what was originally loaded, then generate change package command.
  1258.  
  1259. if ((PartDevChange[i] != "") && (PartDevChange[i] != PartDev[i]))
  1260. printf("CHANGE PACKAGE %s '%s';\n", PartName[i], PartDevChange[i]);
  1261. }
  1262.  
  1263. printf("EDIT .s1;\n");
  1264. printf("SET UNDO_LOG ON;\n");
  1265. }
  1266.  
  1267. PartNumModified = 0;
  1268.  
  1269. return !fileerror();
  1270. }
  1271.  
  1272. void ApplyScriptData()
  1273. {
  1274. string fname;
  1275.  
  1276. if (dlgMessageBox("Exit and apply all updates to the schematic?", "+&OK", "-Cancel") != 0)
  1277. return;
  1278.  
  1279. schematic(SCH)
  1280. {
  1281. fname = filesetext(SCH.name, "_UpdateAll.scr");
  1282. }
  1283.  
  1284. if (!fname)
  1285. return;
  1286.  
  1287. if (!WriteScriptData(fname))
  1288. return;
  1289.  
  1290. string cmd;
  1291. sprintf(cmd, "SCRIPT '%s';\n", fname);
  1292. exit(cmd);
  1293. }
RAW Paste Data