48 if( aLine.size() < 3 || aLine[0] !=
'*' )
51 size_t endPos = aLine.find(
'*', 1 );
52 return endPos != std::string::npos && endPos > 1;
58 if( aLine.size() < 3 || aLine[0] !=
'*' )
61 size_t endPos = aLine.find(
'*', 1 );
63 if( endPos == std::string::npos || endPos <= 1 )
66 return aLine.substr( 1, endPos - 1 );
87 std::ifstream file( aFileName );
97 std::vector<std::string> lines;
100 while( std::getline( file, line ) )
102 if( !line.empty() && line.back() ==
'\r' )
105 lines.push_back( line );
128 for(
size_t i = 1; i < lines.size(); i++ )
131 const std::string& currentLine = lines[i];
133 if( currentLine.empty() )
137 if( currentLine.find(
"*REMARK*" ) == 0 )
145 if( sectionName ==
"SCH" )
149 else if( sectionName ==
"CAM" || sectionName ==
"MISC" )
153 else if( sectionName ==
"FIELDS" )
157 else if( sectionName ==
"SHT" )
161 else if( sectionName ==
"CAE" )
165 else if( sectionName ==
"TEXT" )
169 else if( sectionName ==
"LINES" )
173 else if( sectionName ==
"CAEDECAL" )
177 else if( sectionName ==
"PARTTYPE" )
181 else if( sectionName ==
"PART" )
185 else if( sectionName ==
"BUSSES" )
190 else if( sectionName ==
"OFFPAGE REFS" )
194 else if( sectionName ==
"TIEDOTS" )
198 else if( sectionName ==
"CONNECTION" )
202 else if( sectionName ==
"NETNAMES" )
206 else if( sectionName ==
"END" )
226 for(
auto& attr : part.attributes )
228 if( attr.name ==
"Ref.Des." && attr.value.empty() )
229 attr.value = part.reference;
231 auto ovr = part.attr_overrides.find( attr.name );
233 if( ovr != part.attr_overrides.end() && attr.value.empty() )
234 attr.value = ovr->second;
242 std::ifstream file( aFileName );
244 if( !file.is_open() )
247 std::string firstLine;
249 if( !std::getline( file, firstLine ) )
252 if( !firstLine.empty() && firstLine.back() ==
'\r' )
253 firstLine.pop_back();
255 if( firstLine.find(
"*PADS-LOGIC" ) == 0 )
258 if( firstLine.find(
"*PADS-POWERLOGIC" ) == 0 )
267 if( aLine.empty() || aLine[0] !=
'*' )
270 size_t endPos = aLine.find(
'*', 1 );
272 if( endPos == std::string::npos )
275 std::string headerTag = aLine.substr( 1, endPos - 1 );
280 std::regex headerRegex( R
"(PADS-(POWER)?LOGIC-V(\d+\.\d+)(?:-([A-Za-z0-9]+))?)" );
283 if( !std::regex_match( headerTag, match, headerRegex ) )
286 if( match[1].matched )
287 m_header.product =
"PADS-POWERLOGIC";
291 m_header.version =
"V" + match[2].str();
293 if( match[3].matched )
296 if( endPos + 1 < aLine.size() )
298 std::string desc = aLine.substr( endPos + 1 );
299 size_t start = desc.find_first_not_of(
' ' );
301 if( start != std::string::npos )
302 m_header.description = desc.substr( start );
311 size_t i = aStartLine + 1;
313 while( i < aLines.size() )
315 const std::string& line = aLines[i];
326 std::istringstream iss( line );
330 if( keyword ==
"UNITS" )
343 else if( keyword ==
"CUR" )
349 if( second ==
"SHEET" )
352 else if( keyword ==
"SHEET" )
358 if( second ==
"SIZE" )
360 std::string sizeCode;
365 if( sizeCode ==
"A" )
370 else if( sizeCode ==
"B" )
375 else if( sizeCode ==
"C" )
380 else if( sizeCode ==
"D" )
385 else if( sizeCode ==
"E" )
392 else if( keyword ==
"USERGRID" )
396 else if( keyword ==
"LINEWIDTH" )
400 else if( keyword ==
"CONNWIDTH" )
404 else if( keyword ==
"BUSWIDTH" )
408 else if( keyword ==
"BUSANGLE" )
412 else if( keyword ==
"TEXTSIZE" )
417 else if( keyword ==
"PINNAMESIZE" )
421 else if( keyword ==
"REFNAMESIZE" )
425 else if( keyword ==
"PARTNAMESIZE" )
429 else if( keyword ==
"PINNOSIZE" )
433 else if( keyword ==
"NETNAMESIZE" )
437 else if( keyword ==
"DOTGRID" )
441 else if( keyword ==
"TIEDOTSIZE" )
445 else if( keyword ==
"REAL" )
451 if( second ==
"WIDTH" )
454 else if( keyword ==
"FONT" )
460 if( second ==
"MODE" )
463 else if( keyword ==
"DEFAULT" )
469 if( second ==
"FONT" )
472 std::getline( iss, rest );
473 size_t start = rest.find(
'"' );
475 if( start != std::string::npos )
477 size_t end = rest.find(
'"', start + 1 );
479 if(
end != std::string::npos )
484 else if( keyword ==
"BORDER" )
490 if( second ==
"NAME" )
502 else if( keyword ==
"JOBNAME" )
505 std::getline( iss, rest );
506 size_t start = rest.find_first_not_of(
" \t" );
508 if( start != std::string::npos )
510 rest = rest.substr( start );
512 if( rest.size() >= 2 && rest.front() ==
'"' && rest.back() ==
'"' )
513 rest = rest.substr( 1, rest.size() - 2 );
519 else if( keyword ==
"NTXCOL" || keyword ==
"HIRCOL" || keyword ==
"LINCOL" ||
520 keyword ==
"TXTCOL" || keyword ==
"CONCOL" || keyword ==
"BUSCOL" ||
521 keyword ==
"PTXCOL" || keyword ==
"COMCOL" || keyword ==
"NMCOL" ||
522 keyword ==
"PNMCOL" || keyword ==
"PINCOL" || keyword ==
"NETCOL" ||
523 keyword ==
"FBGCOL" || keyword ==
"FIELDCOL" ||
524 keyword ==
"NNVISPWRGND" || keyword ==
"PCBFLAGS" ||
525 keyword ==
"JOBTIME" || keyword ==
"BACKUPTIME" ||
526 keyword ==
"OFFREFVIEW" || keyword ==
"OFFREFNUM" ||
527 keyword ==
"SHEETNUMSEP" )
535 return aLines.size() - 1;
541 size_t i = aStartLine + 1;
543 while( i < aLines.size() )
545 const std::string& line = aLines[i];
550 if( line.empty() || line[0] !=
'"' )
557 size_t closeQuote = line.find(
'"', 1 );
559 if( closeQuote != std::string::npos )
561 std::string fieldName = line.substr( 1, closeQuote - 1 );
562 std::string fieldValue;
564 if( closeQuote + 1 < line.size() )
566 fieldValue = line.substr( closeQuote + 1 );
567 size_t start = fieldValue.find_first_not_of(
" \t" );
569 if( start != std::string::npos )
570 fieldValue = fieldValue.substr( start );
581 return aLines.size() - 1;
588 const std::string& line = aLines[aStartLine];
589 std::string afterMarker = line.substr( line.find(
'*', 1 ) + 1 );
591 std::istringstream iss( afterMarker );
606 size_t i = aStartLine + 1;
608 while( i < aLines.size() )
610 const std::string& line = aLines[i];
618 return aLines.size() - 1;
624 size_t i = aStartLine + 1;
626 while( i < aLines.size() )
628 const std::string& line = aLines[i];
642 std::istringstream iss( line );
653 std::getline( iss, rest );
654 size_t qStart = rest.find(
'"' );
656 if( qStart != std::string::npos )
658 size_t qEnd = rest.find(
'"', qStart + 1 );
660 if( qEnd != std::string::npos )
661 item.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
667 if( i < aLines.size() )
674 return aLines.size() - 1;
680 size_t i = aStartLine + 1;
682 while( i < aLines.size() )
684 const std::string& line = aLines[i];
696 if( line.find(
"LINES" ) != std::string::npos )
699 std::istringstream iss( line );
700 std::string
name, keyword;
705 if( keyword ==
"LINES" )
715 while( i < aLines.size() )
717 const std::string& pline = aLines[i];
729 if( pline.find(
"LINES" ) != std::string::npos )
731 std::istringstream tiss( pline );
732 std::string tname, tkw;
733 tiss >> tname >> tkw;
739 std::istringstream piss( pline );
740 std::string firstToken;
743 if( firstToken ==
"OPEN" || firstToken ==
"CLOSED" ||
744 firstToken ==
"CIRCLE" || firstToken ==
"COPCLS" )
756 && ( std::isdigit( firstToken[0] )
757 || firstToken[0] ==
'-'
758 || firstToken[0] ==
'+' );
760 if(
isNumber && pline.find(
'"' ) != std::string::npos )
765 std::istringstream tiss( pline );
768 tiss >> tx >> ty >>
text.rotation >>
text.justification >>
text.height
769 >>
text.width_factor;
771 text.position.x = tx;
772 text.position.y = ty;
775 std::getline( tiss, trest );
776 size_t qStart = trest.find(
'"' );
778 if( qStart != std::string::npos )
780 size_t qEnd = trest.find(
'"', qStart + 1 );
782 if( qEnd != std::string::npos )
783 text.font_name = trest.substr( qStart + 1, qEnd - qStart - 1 );
788 if( i < aLines.size() )
789 text.content = aLines[i];
805 return aLines.size() - 1;
812 size_t i = aStartLine + 1;
814 while( i < aLines.size() )
816 const std::string& line = aLines[i];
831 if( !symbol.
name.empty() )
840 std::map<std::string, double> pinDecalLengths;
844 if( !sym.is_pin_decal )
847 for(
const auto& graphic : sym.graphics )
852 if( graphic.points.size() < 2 )
855 const auto& first = graphic.points.front().coord;
856 const auto& last = graphic.points.back().coord;
857 double dx = last.x - first.x;
858 double dy = last.y - first.y;
859 pinDecalLengths[sym.name] = std::sqrt( dx * dx + dy * dy );
866 if( sym.is_pin_decal )
869 for(
auto&
pin : sym.pins )
871 if(
pin.pin_decal_name.empty() )
874 auto it = pinDecalLengths.find(
pin.pin_decal_name );
876 if( it != pinDecalLengths.end() )
877 pin.length = it->second;
881 return i > 0 ? i - 1 : aLines.size() - 1;
888 if( aStartLine >= aLines.size() )
891 const std::string& headerLine = aLines[aStartLine];
895 std::istringstream iss( headerLine );
905 std::vector<std::string> tokens;
908 while( iss >> token )
909 tokens.push_back( token );
911 if( tokens.size() >= 12 )
930 if( tokens.size() >= 3 )
942 size_t idx = aStartLine + 1;
944 for(
int p = 0; p < aSymbol.
num_pieces && idx < aLines.size(); p++ )
946 const std::string& gline = aLines[idx];
952 std::istringstream giss( gline );
956 if( typeStr ==
"OPEN" || typeStr ==
"LINE" )
960 giss >> p1.
x >> p1.
y >> p2.
x >> p2.
y;
961 graphic.
points.push_back( { p1, std::nullopt } );
962 graphic.
points.push_back( { p2, std::nullopt } );
965 else if( typeStr ==
"CLOSED" || typeStr ==
"RECT" )
969 giss >> p1.
x >> p1.
y >> p2.
x >> p2.
y;
970 graphic.
points.push_back( { p1, std::nullopt } );
971 graphic.
points.push_back( { p2, std::nullopt } );
974 else if( typeStr ==
"CIRCLE" )
981 aSymbol.
graphics.push_back( graphic );
985 for(
int p = 0; p < aSymbol.
num_pins && idx < aLines.size(); p++ )
987 const std::string& pline = aLines[idx];
993 std::istringstream piss( pline );
994 double orientation = 0;
996 piss >>
pin.position.x >>
pin.position.y >> orientation >>
pin.length;
997 piss >>
pin.number >>
pin.name;
999 pin.rotation = orientation;
1001 std::string typeStr;
1003 if( piss >> typeStr )
1006 aSymbol.
pins.push_back(
pin );
1014 size_t idx = aStartLine + 1;
1017 if( idx < aLines.size() && aLines[idx].find(
"TIMESTAMP" ) == 0 )
1019 std::istringstream tiss( aLines[idx] );
1026 if( idx < aLines.size() && aLines[idx].size() >= 2 && aLines[idx][0] ==
'"' )
1028 size_t qEnd = aLines[idx].find(
'"', 1 );
1030 if( qEnd != std::string::npos )
1031 aSymbol.
font1 = aLines[idx].substr( 1, qEnd - 1 );
1036 if( idx < aLines.size() && aLines[idx].size() >= 2 && aLines[idx][0] ==
'"' )
1038 size_t qEnd = aLines[idx].find(
'"', 1 );
1040 if( qEnd != std::string::npos )
1041 aSymbol.
font2 = aLines[idx].substr( 1, qEnd - 1 );
1047 for(
int a = 0; a < aSymbol.
num_attrs && idx + 1 < aLines.size(); a++ )
1050 std::istringstream aiss( aLines[idx] );
1059 std::getline( aiss, rest );
1060 size_t qStart = rest.find(
'"' );
1062 if( qStart != std::string::npos )
1064 size_t qEnd = rest.find(
'"', qStart + 1 );
1066 if( qEnd != std::string::npos )
1067 attr.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
1072 if( idx < aLines.size() )
1075 aSymbol.
attrs.push_back( attr );
1080 for(
int p = 0; p < aSymbol.
num_pieces && idx < aLines.size(); p++ )
1082 if( aLines[idx].
empty() )
1091 aSymbol.
graphics.push_back( graphic );
1098 while( idx < aLines.size() )
1100 const std::string& tline = aLines[idx];
1109 if( tline.size() > 1 && tline[0] ==
'T' &&
1110 ( std::isdigit(
static_cast<unsigned char>( tline[1] ) ) || tline[1] ==
'-' ) )
1117 std::istringstream tiss( tline );
1120 tiss >> tx >> ty >>
text.rotation >>
text.justification;
1122 int height = 0, width = 0;
1123 tiss >> height >> width;
1125 text.width_factor = width;
1127 text.position.x = tx;
1128 text.position.y = ty;
1132 if( idx < aLines.size() )
1134 text.content = aLines[idx];
1142 for(
int p = 0; p < aSymbol.
num_pins && idx < aLines.size(); p++ )
1144 const std::string& tLine = aLines[idx];
1160 if( tLine.size() > 1 && tLine[0] ==
'T' )
1163 std::string tContent = tLine.substr( 1 );
1164 std::istringstream tiss( tContent );
1165 int tx = 0, ty = 0, angle = 0;
1167 tiss >> tx >> ty >> angle >>
pin.side >>
pin.pn_h >>
pin.pn_w >>
pin.pn_angle
1169 >>
pin.pin_decal_name;
1171 pin.position.x = tx;
1172 pin.position.y = ty;
1173 pin.rotation = angle;
1176 if(
pin.pin_decal_name ==
"PINB" ||
pin.pin_decal_name ==
"PINORB" ||
1177 pin.pin_decal_name ==
"PCLKB" ||
pin.pin_decal_name ==
"PINIEB" ||
1178 pin.pin_decal_name ==
"PINCLKB" )
1180 pin.inverted =
true;
1183 if(
pin.pin_decal_name ==
"PCLK" ||
pin.pin_decal_name ==
"PCLKB" ||
1184 pin.pin_decal_name ==
"PINCLK" ||
pin.pin_decal_name ==
"PINCLKB" )
1192 if(
pin.pin_decal_name.empty() )
1194 else if(
pin.pin_decal_name.find(
"SHORT" ) != std::string::npos )
1196 else if(
pin.pin_decal_name.find(
"LONG" ) != std::string::npos )
1203 if( idx < aLines.size() )
1205 const std::string& pLine = aLines[idx];
1207 if( pLine.size() > 1 && pLine[0] ==
'P' )
1209 std::string pContent = pLine.substr( 1 );
1210 std::istringstream piss( pContent );
1211 int px1 = 0, py1 = 0, px2 = 0, py2 = 0;
1213 piss >> px1 >> py1 >>
pin.pn_off_angle >>
pin.pn_off_just
1214 >> px2 >> py2 >>
pin.pl_off_angle >>
pin.pl_off_just >>
pin.p_flags;
1216 pin.pn_offset.x = px1;
1217 pin.pn_offset.y = py1;
1218 pin.pl_offset.x = px2;
1219 pin.pl_offset.y = py2;
1222 if(
pin.p_flags & 128 )
1231 pin.number = std::to_string( p + 1 );
1233 aSymbol.
pins.push_back(
pin );
1236 return idx > 0 ? idx - 1 : 0;
1243 if( aStartLine >= aLines.size() )
1246 const std::string& headerLine = aLines[aStartLine];
1247 std::istringstream iss( headerLine );
1248 std::string typeStr;
1249 int pointCount = 0, lineWidth = 0, lineStyle = 255;
1251 iss >> typeStr >> pointCount >> lineWidth >> lineStyle;
1256 if( typeStr ==
"OPEN" )
1261 else if( typeStr ==
"CLOSED" )
1266 else if( typeStr ==
"CIRCLE" )
1271 else if( typeStr ==
"COPCLS" )
1278 size_t idx = aStartLine + 1;
1280 for(
int p = 0; p < pointCount && idx < aLines.size(); p++ )
1282 const std::string& ptLine = aLines[idx];
1287 std::istringstream piss( ptLine );
1291 std::vector<std::string> extraTokens;
1294 while( piss >> tok )
1295 extraTokens.push_back( tok );
1297 if( extraTokens.size() >= 6 )
1309 aGraphic.
points.push_back( gpt );
1319 std::set<double> uniqueX, uniqueY;
1321 for(
const auto& pt : aGraphic.
points )
1323 uniqueX.insert( pt.coord.x );
1324 uniqueY.insert( pt.coord.y );
1327 bool isRect = ( uniqueX.size() == 2 && uniqueY.size() == 2 );
1331 double minX = *uniqueX.begin();
1332 double maxX = *uniqueX.rbegin();
1333 double minY = *uniqueY.begin();
1334 double maxY = *uniqueY.rbegin();
1337 aGraphic.
points.push_back( { { minX, minY }, std::nullopt } );
1338 aGraphic.
points.push_back( { { maxX, maxY }, std::nullopt } );
1351 double dx = aGraphic.
points[1].coord.x - aGraphic.
points[0].coord.x;
1352 double dy = aGraphic.
points[1].coord.y - aGraphic.
points[0].coord.y;
1353 aGraphic.
radius = std::sqrt( dx * dx + dy * dy ) / 2.0;
1356 return idx > 0 ? idx - 1 : aStartLine;
1363 size_t i = aStartLine + 1;
1365 while( i < aLines.size() )
1367 const std::string& line = aLines[i];
1380 std::istringstream iss( line );
1384 if( pt.
name.empty() )
1399 if( i < aLines.size() && aLines[i].find(
"TIMESTAMP" ) == 0 )
1401 std::istringstream tiss( aLines[i] );
1408 bool isSpecial = ( pt.
name ==
"$GND_SYMS" || pt.
name ==
"$PWR_SYMS" ||
1409 pt.
name ==
"$OSR_SYMS" );
1414 bool isV52Gates = ( i < aLines.size() && aLines[i].size() >= 3
1415 && aLines[i][0] ==
'G' && aLines[i][1] ==
':' );
1417 if( isSpecial && !isV52Gates )
1420 if( i < aLines.size() )
1422 std::istringstream siss( aLines[i] );
1423 int numVariants = 0;
1427 for(
int v = 0; v < numVariants && i < aLines.size(); v++ )
1430 std::istringstream viss( aLines[i] );
1443 else if( i < aLines.size() )
1447 if( pt.
name ==
"$GND_SYMS" )
1449 else if( pt.
name ==
"$PWR_SYMS" )
1456 while( i < aLines.size() )
1458 const std::string& gline = aLines[i];
1469 std::istringstream giss( gline );
1470 std::string keyword;
1473 if( keyword ==
"GATE" )
1490 for(
int p = 0; p < gate.
num_pins && i < aLines.size(); p++ )
1496 std::istringstream piss( aLines[i] );
1497 std::string pinType;
1499 piss >>
pin.pin_id >>
pin.swap_group >> pinType;
1501 if( !pinType.empty() )
1502 pin.pin_type = pinType[0];
1504 std::string pinName;
1506 if( piss >> pinName )
1507 pin.pin_name = pinName;
1513 pt.
gates.push_back( gate );
1516 else if( keyword.size() >= 3 && keyword[0] ==
'G' && keyword[1] ==
':' )
1525 std::string decalStr = keyword.substr( 2 );
1526 std::istringstream diss( decalStr );
1527 std::string decalName;
1529 while( std::getline( diss, decalName,
':' ) )
1531 if( !decalName.empty() )
1541 while( pinsRead < gate.
num_pins && i < aLines.size() )
1543 const std::string& pline = aLines[i];
1548 if( ( pline[0] ==
'G' && pline.size() >= 2 && pline[1] ==
':' )
1549 || pline.find(
"SIGPIN" ) == 0 )
1554 std::istringstream piss( pline );
1555 std::string pinToken;
1557 while( piss >> pinToken && pinsRead < gate.
num_pins )
1560 std::vector<std::string> fields;
1561 std::istringstream fiss( pinToken );
1564 while( std::getline( fiss, field,
'.' ) )
1565 fields.push_back( field );
1567 if( fields.size() >= 1 )
1568 pin.pin_id = fields[0];
1570 if( fields.size() >= 2 )
1576 if( fields.size() >= 3 && !fields[2].empty() )
1577 pin.pin_type = fields[2][0];
1579 if( fields.size() >= 4 )
1580 pin.pin_name = fields[3];
1595 if( !gate.
pins.empty() )
1601 pt.
gates.push_back( gate );
1604 else if( keyword ==
"CONN" )
1619 std::istringstream diss( aLines[i] );
1620 std::string decalName, pinType;
1621 diss >> decalName >> pinType;
1627 for(
int p = 0; p < numPins && i < aLines.size(); p++ )
1633 std::istringstream piss( aLines[i] );
1634 std::string pinType;
1636 piss >>
pin.pin_id >>
pin.swap_group >> pinType;
1638 if( !pinType.empty() )
1639 pin.pin_type = pinType[0];
1645 pt.
gates.push_back( gate );
1648 else if( keyword ==
"SIGPIN" )
1656 if( token.find(
'.' ) != std::string::npos )
1658 std::vector<std::string> fields;
1659 std::istringstream fiss( token );
1662 while( std::getline( fiss, field,
'.' ) )
1663 fields.push_back( field );
1665 if( fields.size() >= 1 )
1668 if( fields.size() >= 3 )
1694 return aLines.size() - 1;
1701 size_t i = aStartLine + 1;
1704 while( i < aLines.size() && aLines[i].empty() )
1707 while( i < aLines.size() )
1709 const std::string& line = aLines[i];
1721 if( std::isalpha(
static_cast<unsigned char>( line[0] ) ) )
1739 return aLines.size() - 1;
1746 if( aStartLine >= aLines.size() )
1749 const std::string& headerLine = aLines[aStartLine];
1750 std::istringstream iss( headerLine );
1756 std::string refdes, partType;
1757 int x = 0, y = 0, angleCode = 0, mirrorFlag = 0;
1759 iss >> refdes >> partType;
1765 std::string actualPartType;
1766 iss >> actualPartType >> x >> y >> angleCode >> mirrorFlag;
1769 partType = actualPartType;
1773 iss >> y >> angleCode >> mirrorFlag;
1784 case 0: aPart.
rotation = 0.0;
break;
1785 case 1: aPart.
rotation = 90.0;
break;
1786 case 2: aPart.
rotation = 180.0;
break;
1787 case 3: aPart.
rotation = 270.0;
break;
1788 default: aPart.
rotation = angleCode;
break;
1798 if( iss >> variantIdx )
1804 int numAttrs = 0, numDisplayedValues = 0, numPins = 0, unused1 = 0, gateIdx = 0;
1807 if( iss >> aPart.
h1 >> aPart.
w1 >> aPart.
h2 >> aPart.
w2 >> numAttrs >> numDisplayedValues
1808 >> numPins >> unused1 >> gateIdx >> unused2 )
1819 std::istringstream iss2( headerLine );
1827 std::string mirrorStr;
1829 if( iss2 >> mirrorStr )
1831 if( mirrorStr ==
"M" || mirrorStr ==
"Y" || mirrorStr ==
"1" )
1841 size_t sepPos = refdes.rfind(
'-' );
1843 if( sepPos == std::string::npos )
1844 sepPos = refdes.rfind(
'.' );
1846 if( sepPos != std::string::npos && sepPos + 1 < refdes.size() )
1848 char gateLetter = refdes[sepPos + 1];
1850 if( std::isalpha(
static_cast<unsigned char>( gateLetter ) ) )
1855 aPart.
gate_index = std::toupper(
static_cast<unsigned char>( gateLetter ) ) -
'A';
1861 size_t i = aStartLine + 1;
1867 if( i < aLines.size() )
1869 const std::string& fl = aLines[i];
1871 if( fl.size() >= 2 && fl[0] ==
'"' )
1873 size_t qEnd = fl.find(
'"', 1 );
1875 if( qEnd != std::string::npos )
1876 aPart.
font1 = fl.substr( 1, qEnd - 1 );
1882 if( i < aLines.size() )
1884 const std::string& fl = aLines[i];
1886 if( fl.size() >= 2 && fl[0] ==
'"' )
1888 size_t qEnd = fl.find(
'"', 1 );
1890 if( qEnd != std::string::npos )
1891 aPart.
font2 = fl.substr( 1, qEnd - 1 );
1898 for(
int a = 0; a < aPart.
num_attrs && i + 1 < aLines.size(); a++ )
1901 std::istringstream aiss( aLines[i] );
1902 int ax = 0, ay = 0, angle = 0, disp = 0, h = 0, w = 0, vis = 0;
1904 aiss >> ax >> ay >> angle >> disp >> h >> w >> vis;
1918 attr.
visible = ( ( vis & 0x8 ) == 0 );
1922 std::getline( aiss, rest );
1923 size_t qStart = rest.find(
'"' );
1925 if( qStart != std::string::npos )
1927 size_t qEnd = rest.find(
'"', qStart + 1 );
1929 if( qEnd != std::string::npos )
1930 attr.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
1935 if( i < aLines.size() )
1936 attr.
name = aLines[i];
1946 if( !aLines[i].
empty()
1947 && std::isdigit(
static_cast<unsigned char>( aLines[i][0] ) ) )
1952 if( i >= aLines.size() )
1955 const std::string& valLine = aLines[i];
1957 if( valLine.size() > 2 && valLine[0] ==
'"' )
1959 size_t closeQ = valLine.find(
'"', 1 );
1961 if( closeQ != std::string::npos )
1963 std::string attrName = valLine.substr( 1, closeQ - 1 );
1964 std::string attrValue;
1966 if( closeQ + 1 < valLine.size() )
1968 attrValue = valLine.substr( closeQ + 1 );
1969 size_t start = attrValue.find_first_not_of(
" \t" );
1971 if( start != std::string::npos )
1972 attrValue = attrValue.substr( start );
1990 attr.value = it->second;
1994 while( i < aLines.size() )
1996 const std::string& pline = aLines[i];
2005 if( std::isalpha(
static_cast<unsigned char>( pline[0] ) ) )
2009 if( std::isdigit(
static_cast<unsigned char>( pline[0] ) ) )
2012 std::istringstream poiss( pline );
2024 while( i < aLines.size() )
2026 const std::string& attrLine = aLines[i];
2028 if( attrLine.empty() )
2034 if( attrLine[0] ==
'@' )
2037 std::istringstream aiss( attrLine.substr( 1 ) );
2041 std::getline( aiss, rest );
2042 size_t start = rest.find_first_not_of(
" \t" );
2044 if( start != std::string::npos )
2046 rest = rest.substr( start );
2048 if( !rest.empty() && rest[0] ==
'"' )
2050 size_t endQuote = rest.find(
'"', 1 );
2052 if( endQuote != std::string::npos )
2054 attr.
value = rest.substr( 1, endQuote - 1 );
2055 rest = rest.substr( endQuote + 1 );
2060 std::istringstream viss( rest );
2062 std::getline( viss, rest );
2065 std::istringstream piss( rest );
2070 if( piss >> visStr )
2071 attr.
visible = ( visStr !=
"N" && visStr !=
"0" && visStr !=
"H" );
2077 else if( std::isalpha(
static_cast<unsigned char>( attrLine[0] ) ) )
2095 size_t i = aStartLine + 1;
2097 while( i < aLines.size() )
2099 const std::string& line = aLines[i];
2111 if( line.find(
"@@@O" ) == 0 )
2114 std::istringstream iss( line );
2115 std::string idToken;
2119 if( idToken.size() > 4 )
2136 return aLines.size() - 1;
2143 size_t i = aStartLine + 1;
2145 while( i < aLines.size() )
2147 const std::string& line = aLines[i];
2159 if( line.find(
"@@@D" ) == 0 )
2162 std::istringstream iss( line );
2163 std::string idToken;
2166 if( idToken.size() > 4 )
2181 return aLines.size() - 1;
2189 size_t i = aStartLine + 1;
2191 while( i < aLines.size() )
2193 const std::string& line = aLines[i];
2206 if( secName ==
"SIGNAL" )
2211 if( !signal.
name.empty() )
2214 for(
auto& wire : signal.
wires )
2218 for(
const auto& wire : signal.
wires )
2220 for(
const auto& ep : { wire.endpoint_a, wire.endpoint_b } )
2222 if( ep.find(
'.' ) != std::string::npos &&
2223 ep.find(
"@@@" ) == std::string::npos )
2225 size_t dotPos = ep.find(
'.' );
2227 conn.
reference = ep.substr( 0, dotPos );
2236 if( existing.reference == conn.
reference &&
2250 m_signals.push_back( std::move( signal ) );
2265 return aLines.size() - 1;
2272 if( aStartLine >= aLines.size() )
2276 const std::string& headerLine = aLines[aStartLine];
2279 if( secName !=
"SIGNAL" )
2283 size_t afterMarker = headerLine.find(
'*', 1 );
2285 if( afterMarker == std::string::npos )
2288 std::string rest = headerLine.substr( afterMarker + 1 );
2289 std::istringstream iss( rest );
2293 size_t i = aStartLine + 1;
2296 if( aSignal.
flags2 == 1 && i < aLines.size() )
2298 const std::string& funcLine = aLines[i];
2300 if( funcLine.find(
"\"FUNCTION\"" ) != std::string::npos ||
2301 funcLine.find(
"FUNCTION" ) == 0 )
2303 size_t qStart = funcLine.find(
'"' );
2305 if( qStart != std::string::npos )
2307 size_t qEnd = funcLine.find(
'"', qStart + 1 );
2309 if( qEnd != std::string::npos )
2311 size_t afterQ = funcLine.find_first_not_of(
" \t", qEnd + 1 );
2313 if( afterQ != std::string::npos )
2314 aSignal.
function = funcLine.substr( afterQ );
2325 while( i < aLines.size() )
2327 const std::string& line = aLines[i];
2340 std::istringstream wiss( line );
2352 for(
int v = 0; v < wire.
vertex_count && i < aLines.size(); v++ )
2354 const std::string& ptLine = aLines[i];
2360 std::istringstream piss( ptLine );
2361 piss >> pt.
x >> pt.
y;
2373 aSignal.
wires.push_back( wire );
2376 return i > 0 ? i - 1 : aStartLine;
2383 size_t i = aStartLine + 1;
2385 while( i < aLines.size() )
2387 const std::string& line = aLines[i];
2401 std::istringstream iss( line );
2409 std::getline( iss, rest );
2410 size_t qStart = rest.find(
'"' );
2412 if( qStart != std::string::npos )
2414 size_t qEnd = rest.find(
'"', qStart + 1 );
2416 if( qEnd != std::string::npos )
2417 label.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
2424 return aLines.size() - 1;
2431 size_t i = aStartLine + 1;
2433 bool foundFirstBrace =
false;
2435 while( i < aLines.size() )
2437 const std::string& line = aLines[i];
2439 for(
char c : line )
2444 foundFirstBrace =
true;
2452 if( foundFirstBrace && braceDepth <= 0 )
2462 return aLines.size() - 1;
2470 if( sym.name == aName )
2482 if( part.reference == aReference )
2494 if( signal.name == aName )
2506 if( sheets.empty() )
2509 return *sheets.rbegin();
2515 std::set<int> sheets;
2518 sheets.insert(
header.sheet_num );
2521 sheets.insert( part.sheet_number );
2525 for(
const auto& wire : signal.wires )
2526 sheets.insert( wire.sheet_number );
2528 for(
const auto& conn : signal.connections )
2529 sheets.insert( conn.sheet_number );
2532 if( sheets.empty() )
2541 std::vector<SCH_SIGNAL>
result;
2546 filteredSignal.
name = signal.name;
2548 for(
const auto& wire : signal.wires )
2550 if( wire.sheet_number == aSheetNumber )
2551 filteredSignal.
wires.push_back( wire );
2554 for(
const auto& conn : signal.connections )
2556 if( conn.sheet_number == aSheetNumber )
2561 result.push_back( filteredSignal );
2570 std::vector<PART_PLACEMENT>
result;
2574 if( part.sheet_number == aSheetNumber )
2575 result.push_back( part );
2584 std::string upper = aTypeStr;
2585 std::transform( upper.begin(), upper.end(), upper.begin(), ::toupper );
2587 if( upper ==
"I" || upper ==
"IN" || upper ==
"INPUT" || upper ==
"L" )
2590 if( upper ==
"O" || upper ==
"OUT" || upper ==
"OUTPUT" || upper ==
"S" )
2593 if( upper ==
"B" || upper ==
"BI" || upper ==
"BIDIR" || upper ==
"BIDIRECTIONAL" )
2596 if( upper ==
"T" || upper ==
"TRI" || upper ==
"TRISTATE" )
2599 if( upper ==
"OC" || upper ==
"OPENCOLLECTOR" )
2602 if( upper ==
"OE" || upper ==
"OPENEMITTER" )
2605 if( upper ==
"P" || upper ==
"PWR" || upper ==
"POWER" || upper ==
"G" )
2608 if( upper ==
"PAS" || upper ==
"PASSIVE" )
2617 switch( std::toupper( aTypeChar ) )
size_t skipBraceDelimitedSection(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionPARTTYPE(const std::vector< std::string > &aLines, size_t aStartLine)
bool isSectionMarker(const std::string &aLine) const
bool Parse(const std::string &aFileName)
size_t parseSymbolDef(const std::vector< std::string > &aLines, size_t aStartLine, SYMBOL_DEF &aSymbol)
size_t parseSectionSCH(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionCAEDECAL(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< OFF_PAGE_CONNECTOR > m_offPageConnectors
size_t parseSectionTIEDOTS(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parsePartPlacement(const std::vector< std::string > &aLines, size_t aStartLine, PART_PLACEMENT &aPart)
size_t parseSectionSHT(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< SCH_SIGNAL > m_signals
size_t parseSectionOFFPAGEREFS(const std::vector< std::string > &aLines, size_t aStartLine)
std::string extractSectionName(const std::string &aLine) const
size_t parseSectionCONNECTION(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionLINES(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseGraphicPrimitive(const std::vector< std::string > &aLines, size_t aStartLine, SYMBOL_GRAPHIC &aGraphic)
static PIN_TYPE ParsePinTypeChar(char aTypeChar)
bool parseHeader(const std::string &aLine)
std::vector< SHEET_HEADER > m_sheetHeaders
size_t parseSectionNETNAMES(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< SYMBOL_DEF > m_symbolDefs
std::vector< PART_PLACEMENT > m_partPlacements
PIN_TYPE parsePinType(const std::string &aTypeStr)
std::vector< SCH_SIGNAL > GetSignalsOnSheet(int aSheetNumber) const
std::set< int > GetSheetNumbers() const
std::vector< TEXT_ITEM > m_textItems
static bool CheckFileHeader(const std::string &aFileName)
size_t parseSectionTEXT(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSignalDef(const std::vector< std::string > &aLines, size_t aStartLine, SCH_SIGNAL &aSignal)
std::vector< NETNAME_LABEL > m_netNameLabels
std::vector< PART_PLACEMENT > GetPartsOnSheet(int aSheetNumber) const
std::vector< LINES_ITEM > m_linesItems
const SCH_SIGNAL * GetSignal(const std::string &aName) const
std::vector< TIED_DOT > m_tiedDots
std::map< std::string, PARTTYPE_DEF > m_partTypes
const SYMBOL_DEF * GetSymbolDef(const std::string &aName) const
const PART_PLACEMENT * GetPartPlacement(const std::string &aReference) const
size_t parseSectionCAE(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionFIELDS(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionPART(const std::vector< std::string > &aLines, size_t aStartLine)
int GetSheetCount() const
static bool empty(const wxTextEntryBase *aCtrl)
static bool isNumber(const char *cp, const char *limit)
Return true if the next sequence of text is a number: either an integer, fixed point,...
int ParseInt(const std::string &aStr, int aDefault, const std::string &aContext)
Parse integer from string with error context.
double ParseDouble(const std::string &aStr, double aDefault, const std::string &aContext)
Parse double from string with error context.
Common utilities and types for parsing PADS file formats.
std::vector< FAB_LAYER_COLOR > dummy
Attribute label pair from CAEDECAL or PART entries.
Gate definition within a PARTTYPE.
std::vector< std::string > decal_names
std::vector< PARTTYPE_PIN > pins
std::optional< ARC_DATA > arc
Graphical line/shape item from LINES section.
std::vector< TEXT_ITEM > texts
std::vector< SYMBOL_GRAPHIC > primitives
Net name label from NETNAMES section.
Off-page reference from OFFPAGE REFS section.
General schematic parameters from SCH and FIELDS sections.
Part type definition from PARTTYPE section.
std::vector< GATE_DEF > gates
std::vector< SPECIAL_VARIANT > special_variants
std::vector< std::string > swap_lines
std::vector< SIGPIN > sigpins
std::string special_keyword
Pin definition within a PARTTYPE GATE.
Part instance from PART section.
std::string power_net_name
std::map< std::string, std::string > attr_overrides
std::vector< PART_ATTRIBUTE > attributes
std::vector< PIN_OVERRIDE > pin_overrides
Signal (net) definition from CONNECTION and SIGNAL sections.
std::vector< PIN_CONNECTION > connections
std::vector< WIRE_SEGMENT > wires
Symbol definition from CAEDECAL section.
std::vector< SYMBOL_GRAPHIC > graphics
std::vector< SYMBOL_PIN > pins
std::vector< CAEDECAL_ATTR > attrs
std::vector< SYMBOL_TEXT > texts
Graphic primitive from CAEDECAL or LINES sections (OPEN, CLOSED, CIRCLE, COPCLS).
std::vector< GRAPHIC_POINT > points
Pin T/P line pair from CAEDECAL.
Free text item from TEXT section.
Junction dot from TIEDOTS section.
Wire segment connecting two endpoints through coordinate vertices.
std::vector< POINT > vertices
std::vector< std::string > header
wxString result
Test unit parsing edge cases and error handling.