KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sch_io_http_lib.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 Andre F. K. Iwers <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21
22#include <wx/log.h>
23#include <wx/tokenzr.h>
24
25#include <fmt.h>
26#include <lib_symbol.h>
27
30#include "sch_io_http_lib.h"
31#include <ki_exception.h>
32
33
35 SCH_IO( wxS( "HTTP library" ) ),
36 m_adapter( nullptr )
37{
38}
39
40
41void SCH_IO_HTTP_LIB::EnumerateSymbolLib( wxArrayString& aSymbolNameList, const wxString& aLibraryPath,
42 const std::map<std::string, UTF8>* aProperties )
43{
44 wxCHECK_RET( m_adapter, "HTTP plugin missing library manager adapter handle!" );
45 ensureSettings( aLibraryPath );
47
48 if( !m_conn )
50
51 // The name list drives the library tree and only needs part names, which the category
52 // listing already provides. Avoid the per-part detail fetch done by the full enumeration.
53 for( const HTTP_LIB_CATEGORY& category : m_conn->getCategories() )
54 {
55 syncCacheIfStale( category );
56
57 for( const HTTP_LIB_PART& part : m_cachedCategories[category.id].cachedParts )
58 aSymbolNameList.Add( part.name );
59 }
60}
61
62
63void SCH_IO_HTTP_LIB::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList, const wxString& aLibraryPath,
64 const std::map<std::string, UTF8>* aProperties )
65{
66 wxCHECK_RET( m_adapter, "HTTP plugin missing library manager adapter handle!" );
67 ensureSettings( aLibraryPath );
69
70 if( !m_conn )
72
73 bool powerSymbolsOnly = ( aProperties && aProperties->contains( SYMBOL_LIBRARY_ADAPTER::PropPowerSymsOnly ) );
74
75 for( const HTTP_LIB_CATEGORY& category : m_conn->getCategories() )
76 {
77 syncCacheIfStale( category );
78
79 for( HTTP_LIB_PART& part : m_cachedCategories[category.id].cachedParts )
80 {
81 // The category listing may omit fields, so the chooser would show blank columns
82 // until each part is selected individually. Back-fill from the per-part endpoint.
83 if( !part.detailsLoaded )
84 {
85 HTTP_LIB_PART fullPart;
86
87 if( m_conn->SelectOne( part.id, fullPart ) )
88 {
89 // The listing name keys m_cache for LoadSymbol; keep it even if the detail
90 // record reports a different (or missing) name.
91 fullPart.id = part.id;
92 fullPart.name = part.name;
93 part = std::move( fullPart );
94 }
95 }
96
97 wxString libIDString( part.name );
98
99 LIB_SYMBOL* symbol = loadSymbolFromPart( aLibraryPath, libIDString, category, part );
100
101 if( symbol && ( !powerSymbolsOnly || symbol->IsPower() ) )
102 aSymbolList.emplace_back( symbol );
103 }
104 }
105}
106
107
108LIB_SYMBOL* SCH_IO_HTTP_LIB::LoadSymbol( const wxString& aLibraryPath, const wxString& aAliasName,
109 const std::map<std::string, UTF8>* aProperties )
110{
111 wxCHECK_MSG( m_adapter, nullptr, "HTTP plugin missing library manager adapter handle!" );
112 ensureSettings( aLibraryPath );
114
115 if( !m_conn )
117
118 std::string part_id = "";
119
120 std::string partName( aAliasName.ToUTF8() );
121
122 const HTTP_LIB_CATEGORY* foundCategory = nullptr;
124
125 std::vector<HTTP_LIB_CATEGORY> categories = m_conn->getCategories();
126
127 if( m_conn->GetCachedParts().empty() )
128 syncCache();
129
130 std::tuple relations = m_conn->GetCachedParts()[partName];
131 std::string associatedCatID = std::get<1>( relations );
132
133 // get the matching category
134 for( const HTTP_LIB_CATEGORY& categoryIter : categories )
135 {
136 if( categoryIter.id == associatedCatID )
137 {
138 foundCategory = &categoryIter;
139 break;
140 }
141 }
142
143 // return Null if no category was found. This should never happen
144 if( foundCategory == nullptr )
145 {
146 wxLogTrace( traceHTTPLib, wxT( "loadSymbol: no category found for %s" ), partName );
147 return nullptr;
148 }
149
150 // get the matching query ID
151 for( const HTTP_LIB_PART& part : m_cachedCategories[foundCategory->id].cachedParts )
152 {
153 if( part.id == std::get<0>( relations ) )
154 {
155 part_id = part.id;
156 break;
157 }
158 }
159
160 if( m_conn->SelectOne( part_id, result ) )
161 {
162 wxLogTrace( traceHTTPLib, wxT( "LoadSymbol: SelectOne (%s) found in %s" ), part_id, foundCategory->name );
163 }
164 else
165 {
166 wxLogTrace( traceHTTPLib, wxT( "LoadSymbol: SelectOne (%s) failed for category %s" ), part_id,
167 foundCategory->name );
168
170 }
171
172 wxCHECK( foundCategory, nullptr );
173
174 return loadSymbolFromPart( aLibraryPath, aAliasName, *foundCategory, result );
175}
176
177
178void SCH_IO_HTTP_LIB::GetSubLibraryNames( std::vector<wxString>& aNames )
179{
180 aNames.clear();
181
182 ensureSettings( wxEmptyString );
183 connect();
184
185 // connect() leaves m_conn null when the endpoint is unreachable so a network loss
186 // degrades to an empty result instead of a null dereference while building the tree.
187 if( !m_conn )
188 return;
189
190 std::set<wxString> categoryNames;
191
192 for( const HTTP_LIB_CATEGORY& categoryIter : m_conn->getCategories() )
193 {
194 if( categoryNames.count( categoryIter.name ) )
195 continue;
196
197 aNames.emplace_back( categoryIter.name );
198 categoryNames.insert( categoryIter.name );
199 }
200}
201
202
203wxString SCH_IO_HTTP_LIB::GetSubLibraryDescription( const wxString& aName )
204{
205 ensureSettings( wxEmptyString );
206 connect();
207
208 if( !m_conn )
209 return wxEmptyString;
210
211 return m_conn->getCategoryDescription( std::string( aName.mb_str() ) );
212}
213
214
215void SCH_IO_HTTP_LIB::GetAvailableSymbolFields( std::vector<wxString>& aNames )
216{
217 // TODO: Implement this sometime; This is currently broken...
218 std::copy( m_customFields.begin(), m_customFields.end(), std::back_inserter( aNames ) );
219}
220
221
222void SCH_IO_HTTP_LIB::GetDefaultSymbolFields( std::vector<wxString>& aNames )
223{
224 std::copy( m_defaultShownFields.begin(), m_defaultShownFields.end(), std::back_inserter( aNames ) );
225}
226
227
228void SCH_IO_HTTP_LIB::ensureSettings( const wxString& aSettingsPath )
229{
230 auto tryLoad =
231 [&]()
232 {
233 if( !m_settings->LoadFromFile() )
234 {
235 THROW_IO_ERROR( wxString::Format( _( "HTTP library settings file %s missing or invalid." ),
236 aSettingsPath ) );
237 }
238
239 if( m_settings->m_Source.api_version.empty() )
240 {
241 THROW_IO_ERROR( wxString::Format( _( "HTTP library settings file %s is missing the API version "
242 "number." ),
243 aSettingsPath ) );
244 }
245
246 if( m_settings->getSupportedAPIVersion() != m_settings->m_Source.api_version )
247 {
248 THROW_IO_ERROR( wxString::Format( _( "HTTP library settings file %s uses API version %s, but "
249 "KiCad requires version %s." ),
250 aSettingsPath, m_settings->m_Source.api_version,
251 m_settings->getSupportedAPIVersion() ) );
252 }
253
254 if( m_settings->m_Source.root_url.empty() )
255 {
256 THROW_IO_ERROR( wxString::Format( _( "HTTP library settings file %s is missing the root URL." ),
257 aSettingsPath ) );
258 }
259
260 // map lib source type
261 m_settings->m_Source.type = m_settings->get_HTTP_LIB_SOURCE_TYPE();
262
263 if( m_settings->m_Source.type == HTTP_LIB_SOURCE_TYPE::INVALID )
264 {
265 THROW_IO_ERROR( wxString::Format( _( "HTTP library settings file %s has invalid library type." ),
266 aSettingsPath ) );
267 }
268
269 // make sure that the root url finishes with a forward slash
270 if( m_settings->m_Source.root_url.at( m_settings->m_Source.root_url.length() - 1 ) != '/' )
271 m_settings->m_Source.root_url += "/";
272
273 // Append api version to root URL
274 m_settings->m_Source.root_url += m_settings->m_Source.api_version + "/";
275 };
276
277 if( !m_settings && !aSettingsPath.IsEmpty() )
278 {
279 std::string path( aSettingsPath.ToUTF8() );
280 m_settings = std::make_unique<HTTP_LIB_SETTINGS>( path );
281
282 m_settings->SetReadOnly( true );
283
284 tryLoad();
285 }
286 else if( m_settings )
287 {
288 // If we have valid settings but no connection yet; reload settings in case user is editing
289 tryLoad();
290 }
291 else if( !m_settings )
292 {
293 wxLogTrace( traceHTTPLib, wxT( "ensureSettings: no settings available!" ) );
294 }
295}
296
297
299{
300 wxCHECK_RET( m_settings, "Call ensureSettings before ensureConnection!" );
301
302 connect();
303
304 if( !m_conn || !m_conn->IsValidEndpoint() )
305 {
306 THROW_IO_ERROR( wxString::Format( _( "Could not connect to %s. Errors: %s" ),
307 m_settings->m_Source.root_url,
308 m_lastError ) );
309 }
310}
311
312
314{
315 wxCHECK_RET( m_settings, "Call ensureSettings before connect()!" );
316
317 if( !m_conn )
318 {
319 m_conn = std::make_unique<HTTP_LIB_CONNECTION>( m_settings->m_Source, true );
320
321 if( !m_conn->IsValidEndpoint() )
322 {
323 m_lastError = m_conn->GetLastError();
324
325 // Make sure we release pointer so we are able to query API again next time
326 m_conn.reset();
327
328 return;
329 }
330 }
331}
332
333
335{
336 for( const HTTP_LIB_CATEGORY& category : m_conn->getCategories() )
337 syncCache( category );
338}
339
340
342{
343 auto it = m_cachedCategories.find( category.id );
344
345 if( it != m_cachedCategories.end()
346 && std::difftime( std::time( nullptr ), it->second.lastCached )
347 < m_settings->m_Source.timeout_categories )
348 {
349 return;
350 }
351
352 syncCache( category );
353}
354
355
357{
358 std::vector<HTTP_LIB_PART> found_parts;
359
360 if( !m_conn->SelectAll( category, found_parts ) )
361 {
362 if( !m_conn->GetLastError().empty() )
363 {
364 THROW_IO_ERROR( wxString::Format( _( "Error retrieving data from HTTP library %s: %s" ),
365 category.name,
366 m_conn->GetLastError() ) );
367 }
368
369 return;
370 }
371
372 // remove cached parts
373 m_cachedCategories[category.id].cachedParts.clear();
374
375 // Copy newly cached data across
376 m_cachedCategories[category.id].cachedParts = found_parts;
377 m_cachedCategories[category.id].lastCached = std::time( nullptr );
378}
379
380
381LIB_SYMBOL* SCH_IO_HTTP_LIB::loadSymbolFromPart( const wxString& aLibraryPath,
382 const wxString& aSymbolName,
383 const HTTP_LIB_CATEGORY& aCategory,
384 const HTTP_LIB_PART& aPart )
385{
386 LIB_SYMBOL* symbol = nullptr;
387 LIB_SYMBOL* originalSymbol = nullptr;
388 LIB_ID symbolId;
389
390 std::string symbolIdStr = aPart.symbolIdStr;
391
392 // Extract library nickname from the library path (e.g., "/path/to/W5.kicad_httplib" -> "W5")
393 wxFileName libFileName( aLibraryPath );
394 wxString libNickname = libFileName.GetName();
395
396 // Get or Create the symbol using the found symbol
397 if( !symbolIdStr.empty() )
398 {
399 symbolId.Parse( symbolIdStr );
400
401 if( symbolId.IsValid() )
402 originalSymbol = m_adapter->LoadSymbol( symbolId );
403
404 if( originalSymbol )
405 {
406 wxLogTrace( traceHTTPLib, wxT( "loadSymbolFromPart: found original symbol '%s'" ), symbolIdStr );
407
408 symbol = originalSymbol->Duplicate();
409 symbol->SetSourceLibId( symbolId );
410 symbol->SetName( aSymbolName );
411
412 LIB_ID libId = symbol->GetLibId();
413 libId.SetLibNickname( libNickname );
414 libId.SetSubLibraryName( aCategory.name );
415 symbol->SetLibId( libId );
416 }
417 else if( !symbolId.IsValid() )
418 {
419 wxLogTrace( traceHTTPLib, wxT( "loadSymbolFromPart: source symbol id '%s' is invalid, "
420 "will create empty symbol" ), symbolIdStr );
421 }
422 else
423 {
424 wxLogTrace( traceHTTPLib, wxT( "loadSymbolFromPart: source symbol '%s' not found, "
425 "will create empty symbol" ), symbolIdStr );
426 }
427 }
428
429 if( !symbol )
430 {
431 // Actual symbol not found: return metadata only; error will be
432 // indicated in the symbol chooser
433 symbol = new LIB_SYMBOL( aSymbolName );
434
435 LIB_ID libId = symbol->GetLibId();
436 libId.SetLibNickname( libNickname );
437 libId.SetSubLibraryName( aCategory.name );
438 symbol->SetLibId( libId );
439 }
440
441 symbol->SetExcludedFromBOM( aPart.exclude_from_bom );
443 symbol->SetExcludedFromSim( aPart.exclude_from_sim );
444
445 wxArrayString fp_filters;
446
447 for( auto& [fieldName, fieldProperties] : aPart.fields )
448 {
449 wxString lowerFieldName = wxString( fieldName ).Lower();
450
451 if( lowerFieldName == footprint_field )
452 {
453 SCH_FIELD* field = &symbol->GetFootprintField();
454 wxStringTokenizer tokenizer( std::get<0>( fieldProperties ), ";\t\r\n", wxTOKEN_STRTOK );
455
456 while( tokenizer.HasMoreTokens() )
457 fp_filters.Add( tokenizer.GetNextToken() );
458
459 if( fp_filters.size() > 0 )
460 field->SetText( fp_filters[0] );
461
462 field->SetVisible( std::get<1>( fieldProperties ) );
463 }
464 else if( lowerFieldName == description_field )
465 {
466 SCH_FIELD* field = &symbol->GetDescriptionField();
467 field->SetText( std::get<0>( fieldProperties ) );
468 field->SetVisible( std::get<1>( fieldProperties ) );
469 }
470 else if( lowerFieldName == value_field )
471 {
472 SCH_FIELD* field = &symbol->GetValueField();
473 field->SetText( std::get<0>( fieldProperties ) );
474 field->SetVisible( std::get<1>( fieldProperties ) );
475 }
476 else if( lowerFieldName == datasheet_field )
477 {
478 SCH_FIELD* field = &symbol->GetDatasheetField();
479 field->SetText( std::get<0>( fieldProperties ) );
480 field->SetVisible( std::get<1>( fieldProperties ) );
481 }
482 else if( lowerFieldName == reference_field )
483 {
484 SCH_FIELD* field = &symbol->GetReferenceField();
485 field->SetText( std::get<0>( fieldProperties ) );
486 field->SetVisible( std::get<1>( fieldProperties ) );
487 }
488 else if( lowerFieldName == keywords_field )
489 {
490 symbol->SetKeyWords( std::get<0>( fieldProperties ) );
491 }
492 else
493 {
494 // Check if field exists, if so replace Text and adjust visiblity.
495 //
496 // This proves useful in situations where, for instance, an individual requires a particular value, such as
497 // the material type showcased at a specific position for a capacitor. Subsequently, this value could be defined
498 // in the symbol itself and then, potentially, be modified by the HTTP library as necessary.
499 SCH_FIELD* field = symbol->GetField( fieldName );
500
501 if( field != nullptr )
502 {
503 // adjust values accordingly
504 field->SetText( std::get<0>( fieldProperties ) );
505 field->SetVisible( std::get<1>( fieldProperties ) );
506 }
507 else
508 {
509 // Generic fields
510 field = new SCH_FIELD( symbol, FIELD_T::USER );
511 field->SetName( fieldName );
512
513 field->SetText( std::get<0>( fieldProperties ) );
514 field->SetVisible( std::get<1>( fieldProperties ) );
515 symbol->AddField( field );
516
517 m_customFields.insert( fieldName );
518 }
519 }
520 }
521
522 symbol->SetDescription( aPart.desc );
523 symbol->SetKeyWords( aPart.keywords );
524
525 for( const std::string& filter : aPart.fp_filters )
526 fp_filters.push_back( filter );
527
528 symbol->SetFPFilters( fp_filters );
529
530 // Pin-to-pad maps (issue #2282): attach non-destructively. Prefer the spec-form named maps +
531 // associations when the payload supplies them; otherwise fall back to the legacy flat form for
532 // one release, bound to the symbol's concrete Footprint field (fp_filters may carry globs).
533 if( !aPart.named_pin_maps.IsEmpty() || !aPart.associated_footprints.empty() )
534 {
535 symbol->SetPinMaps( aPart.named_pin_maps );
537 }
538 else
539 {
540 const wxString assignedFootprint = symbol->GetFootprintField().GetText();
541
542 if( !aPart.pin_map.empty() && !assignedFootprint.IsEmpty() )
543 {
544 const wxString mapName = wxS( "HTTP Library" );
545
546 symbol->PinMaps().AddOrReplace( MakeLegacyPinMap( mapName, aPart.pin_map ) );
547
548 LIB_ID fpId;
549 fpId.Parse( assignedFootprint );
550 symbol->SetAssociatedFootprints( { { fpId, mapName } } );
551 }
552 }
553
554 return symbol;
555}
556
557void SCH_IO_HTTP_LIB::SaveSymbol( const wxString& aLibraryPath, const LIB_SYMBOL* aSymbol,
558 const std::map<std::string, UTF8>* aProperties )
559{
560 // TODO: Implement this sometime;
561}
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
void SetSubLibraryName(const UTF8 &aName)
Definition lib_id.h:127
Define a library symbol object.
Definition lib_symbol.h:80
SCH_FIELD & GetDescriptionField()
Return reference to the description field.
Definition lib_symbol.h:394
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:149
bool IsPower() const override
void SetSourceLibId(const LIB_ID &aLibId)
Definition lib_symbol.h:153
SCH_FIELD & GetDatasheetField()
Return reference to the datasheet field.
Definition lib_symbol.h:390
virtual LIB_SYMBOL * Duplicate() const
Create a copy of a LIB_SYMBOL and assigns unique KIIDs to the copy and its children.
Definition lib_symbol.h:94
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
SCH_FIELD & GetFootprintField()
Return reference to the footprint field.
Definition lib_symbol.h:386
void SetAssociatedFootprints(std::vector< ASSOCIATED_FOOTPRINT > aList)
Definition lib_symbol.h:228
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
void SetKeyWords(const wxString &aKeyWords)
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:378
void SetPinMaps(const PIN_MAP_SET &aPinMaps)
Definition lib_symbol.h:224
void SetFPFilters(const wxArrayString &aFilters)
Definition lib_symbol.h:206
void SetLibId(const LIB_ID &aLibId)
void AddField(SCH_FIELD *aField)
Add a field.
PIN_MAP_SET & PinMaps()
Definition lib_symbol.h:223
virtual void SetName(const wxString &aName)
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:382
bool IsEmpty() const
Definition pin_map.h:139
void AddOrReplace(PIN_MAP aMap)
Insert aMap, replacing any existing entry with the same name.
Definition pin_map.cpp:113
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
std::unique_ptr< HTTP_LIB_CONNECTION > m_conn
Generally will be null if no valid connection is established.
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
std::unique_ptr< HTTP_LIB_SETTINGS > m_settings
wxString GetSubLibraryDescription(const wxString &aName) override
Gets a description of a sublibrary.
SYMBOL_LIBRARY_ADAPTER * m_adapter
void ensureSettings(const wxString &aSettingsPath)
std::set< wxString > m_customFields
void GetDefaultSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that should be shown by default for this library in the symb...
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
std::set< wxString > m_defaultShownFields
void syncCacheIfStale(const HTTP_LIB_CATEGORY &category)
Refresh the cached parts for a category if it has never been cached or has expired.
LIB_SYMBOL * loadSymbolFromPart(const wxString &aLibraryPath, const wxString &aSymbolName, const HTTP_LIB_CATEGORY &aCategory, const HTTP_LIB_PART &aPart)
wxString description_field
std::map< std::string, HTTP_LIB_CATEGORY > m_cachedCategories
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
void GetSubLibraryNames(std::vector< wxString > &aNames) override
Retrieves a list of sub-libraries in this library.
SCH_IO(const wxString &aName)
Definition sch_io.h:375
static const char * PropPowerSymsOnly
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
Definition symbol.h:206
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
Definition symbol.h:176
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
Definition symbol.h:191
#define _(s)
const char *const traceHTTPLib
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
PIN_MAP MakeLegacyPinMap(const wxString &aName, const std::unordered_map< wxString, std::vector< wxString > > &aAssignments)
Build a single named PIN_MAP from a legacy symbol-pin to footprint-pad(s) assignment table (the flat ...
Definition pin_map.cpp:151
std::string id
id of category
std::string name
name of category
std::vector< ASSOCIATED_FOOTPRINT > associated_footprints
std::string symbolIdStr
std::unordered_map< wxString, std::vector< wxString > > pin_map
Legacy flat MR !2540 pin assignment table (read for one release; issue #2282).
std::string keywords
std::vector< std::string > fp_filters
std::vector< std::pair< std::string, field_type > > fields
PIN_MAP_SET named_pin_maps
Spec-form named pin maps and their footprint associations (issue #2282).
@ USER
The field ID hasn't been set yet; field is invalid.
std::string path
wxString result
Test unit parsing edge cases and error handling.