/**************************************/ /* annotate.cpp: component annotation */ /**************************************/ #include "fctsys.h" #include "common.h" #include "program.h" #include "libcmp.h" #include "netlist.h" #include "protos.h" /* Local Functions*/ static int ListeComposants( CmpListStruct* BaseListeCmp, DrawSheetPath* sheet ); static void BreakReference( CmpListStruct* BaseListeCmp, int NbOfCmp ); static void ReAnnotateComponents( CmpListStruct* BaseListeCmp, int NbOfCmp ); static void ComputeReferenceNumber( CmpListStruct* BaseListeCmp, int NbOfCmp ); int GetLastReferenceNumber( CmpListStruct* Objet, CmpListStruct* BaseListeCmp, int NbOfCmp ); static int ExistUnit( CmpListStruct* Objet, int Unit, CmpListStruct* BaseListeCmp, int NbOfCmp ); /******************************************************/ void WinEDA_SchematicFrame::UpdateSheetNumberAndDate() /******************************************************/ /* Set a sheet number, the sheet count for sheets in the whole schematic * and update the date in all screens */ { wxString date = GenDate(); EDA_ScreenList s_list; // Set the date for ( SCH_SCREEN * screen = s_list.GetFirst(); screen != NULL; screen = s_list.GetNext() ) screen->m_Date = date; // Set sheet counts SetSheetNumberAndCount(); } /***************************************************************************** * Used to annotate the power symbols, before testing erc or computing * netlist when a component reannotation is not necessary * * In order to avoid conflicts the reference number starts with a 0. A * PWR with id 12 is named PWR12 in global annotation and PWR012 by the * Power annotation. ****************************************************************************/ void ReAnnotatePowerSymbolsOnly( void ) { /* Build the screen list (screen, not sheet) */ EDA_SheetList SheetList( NULL ); DrawSheetPath* sheet; int CmpNumber = 1; for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) { EDA_BaseStruct* DrawList = sheet->LastDrawList(); for( ; DrawList != NULL; DrawList = DrawList->Pnext ) { if( DrawList->Type() != TYPE_SCH_COMPONENT ) continue; SCH_COMPONENT* DrawLibItem = (SCH_COMPONENT*) DrawList; EDA_LibComponentStruct* Entry = FindLibPart( DrawLibItem->m_ChipName.GetData(), wxEmptyString, FIND_ROOT ); if( (Entry == NULL) || (Entry->m_Options != ENTRY_POWER) ) continue; //DrawLibItem->ClearAnnotation(sheet); this clears all annotation :( wxString refstr = DrawLibItem->m_PrefixString; //str will be "C?" or so after the ClearAnnotation call. while( refstr.Last() == '?' ) refstr.RemoveLast(); if( !refstr.StartsWith( wxT( "#" ) ) ) refstr = wxT( "#" ) + refstr; refstr << wxT( "0" ) << CmpNumber; DrawLibItem->SetRef( sheet, refstr ); CmpNumber++; } } } /* qsort function to annotate items by their position. * Components are sorted * by reference * if same reference: by sheet * if same sheet, by X pos * if same X pos, by Y pos * if same Y pos, by time stamp */ int AnnotateBy_X_Position( const void* o1, const void* o2 ) { CmpListStruct* item1 = (CmpListStruct*) o1; CmpListStruct* item2 = (CmpListStruct*) o2; int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 ); if( ii == 0 ) ii = item1->m_SheetList.Cmp( item2->m_SheetList ); if( ii == 0 ) ii = item1->m_Pos.x - item2->m_Pos.x; if( ii == 0 ) ii = item1->m_Pos.y - item2->m_Pos.y; if( ii == 0 ) ii = item1->m_TimeStamp - item2->m_TimeStamp; return ii; } /* qsort function to annotate items by their position. * Components are sorted * by reference * if same reference: by sheet * if same sheet, by Y pos * if same Y pos, by X pos * if same X pos, by time stamp */ int AnnotateBy_Y_Position( const void* o1, const void* o2 ) { CmpListStruct* item1 = (CmpListStruct*) o1; CmpListStruct* item2 = (CmpListStruct*) o2; int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 ); if( ii == 0 ) ii = item1->m_SheetList.Cmp( item2->m_SheetList ); if( ii == 0 ) ii = item1->m_Pos.y - item2->m_Pos.y; if( ii == 0 ) ii = item1->m_Pos.x - item2->m_Pos.x; if( ii == 0 ) ii = item1->m_TimeStamp - item2->m_TimeStamp; return ii; } /***************************************************************************** * qsort function to annotate items by value * Components are sorted * by reference * if same reference: by value * if same value: by unit number * if same unit number, by sheet * if same sheet, by time stamp *****************************************************************************/ int AnnotateByValue( const void* o1, const void* o2 ) { CmpListStruct* item1 = (CmpListStruct*) o1; CmpListStruct* item2 = (CmpListStruct*) o2; int ii = strnicmp( item1->m_TextRef, item2->m_TextRef, 32 ); if( ii == 0 ) ii = strnicmp( item1->m_TextValue, item2->m_TextValue, 32 ); if( ii == 0 ) ii = item1->m_Unit - item2->m_Unit; if( ii == 0 ) ii = item1->m_SheetList.Cmp( item2->m_SheetList ); if( ii == 0 ) ii = item1->m_Pos.x - item2->m_Pos.x; if( ii == 0 ) ii = item1->m_Pos.y - item2->m_Pos.y; if( ii == 0 ) ii = item1->m_TimeStamp - item2->m_TimeStamp; return ii; } /**************************************************************************************/ void WinEDA_SchematicFrame::DeleteAnnotation( bool aCurrentSheetOnly, bool aRedraw ) /**************************************************************************************/ /** Function DeleteAnnotation * Remove current component annotations * @param aCurrentSheetOnly : if false: remove all annotations, else remove annotation relative to the current sheet only * @param aRedraw : true to refresh display */ { EDA_BaseStruct* strct; SCH_SCREEN* screen; EDA_ScreenList ScreenList; screen = ScreenList.GetFirst(); if( aCurrentSheetOnly ) screen = GetScreen(); if( screen == NULL ) return; while( screen ) { strct = screen->EEDrawList; for( ; strct; strct = strct->Pnext ) { if( strct->Type() == TYPE_SCH_COMPONENT ) { if( aCurrentSheetOnly ) ( (SCH_COMPONENT*) strct )->ClearAnnotation( m_CurrentSheet ); else ( (SCH_COMPONENT*) strct )->ClearAnnotation( NULL ); } } screen->SetModify(); if( aCurrentSheetOnly ) break; screen = ScreenList.GetNext(); } //update the References m_CurrentSheet->UpdateAllScreenReferences(); if( aRedraw ) DrawPanel->Refresh( true ); } /***************************************************************************** * AnnotateComponents: * * Compute the annotation of the components for the whole project, or the * current sheet only. All the components or the new ones only will be * annotated. * @param parent = Schematic frame * @param annotateSchematic : true = entire schematic annotation, false = current scheet only * @param sortOption : 0 = annotate by sorting X position, * 1 = annotate by sorting Y position, * 2 = annotate by sorting value * @param resetAnnotation : true = remove previous annotation false = anotate new components only *****************************************************************************/ void AnnotateComponents( WinEDA_SchematicFrame* parent, bool annotateSchematic, int sortOption, bool resetAnnotation ) { int ii, NbOfCmp; DrawSheetPath* sheet; CmpListStruct* BaseListeCmp; wxBusyCursor dummy; /* If it is an annotation for all the components, reset previous * annotation: */ if( resetAnnotation ) parent->DeleteAnnotation( !annotateSchematic, false ); /* Build the sheet list */ EDA_SheetList SheetList( g_RootSheet ); /* Update the sheet number, sheet count and date */ parent->UpdateSheetNumberAndDate(); /* First pass: Component counting */ ii = 0; sheet = parent->GetSheet(); if( annotateSchematic ) { NbOfCmp = 0; for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) NbOfCmp += ListeComposants( NULL, sheet ); } else NbOfCmp = ListeComposants( NULL, sheet ); if( NbOfCmp == 0 ) return; BaseListeCmp = (CmpListStruct*) MyZMalloc( NbOfCmp * sizeof(CmpListStruct) ); /* Second pass : Init data tables */ if( annotateSchematic ) { ii = 0; for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) ii += ListeComposants( BaseListeCmp + ii, sheet ); } else ii = ListeComposants( BaseListeCmp, sheet ); if( ii != NbOfCmp ) DisplayError( parent, wxT( "Internal error in AnnotateComponents()" ) ); /* Break full components reference in name (prefix) and number: * example: IC1 become IC, and 1 */ BreakReference( BaseListeCmp, NbOfCmp ); switch( sortOption ) { case 0: qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct), ( int( * ) ( const void*, const void* ) )AnnotateBy_X_Position ); break; case 1: qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct), ( int( * ) ( const void*, const void* ) )AnnotateBy_Y_Position ); break; case 2: qsort( BaseListeCmp, NbOfCmp, sizeof(CmpListStruct), ( int( * ) ( const void*, const void* ) )AnnotateByValue ); break; } /* Recalculate reference numbers */ ComputeReferenceNumber( BaseListeCmp, NbOfCmp ); ReAnnotateComponents( BaseListeCmp, NbOfCmp ); MyFree( BaseListeCmp ); BaseListeCmp = NULL; /* Final control */ CheckAnnotate( parent, !annotateSchematic ); parent->DrawPanel->Refresh( true ); } /***************************************************************************** * if BaseListeCmp == NULL : count components * else update data table BaseListeCmp *****************************************************************************/ int ListeComposants( CmpListStruct* BaseListeCmp, DrawSheetPath* sheet ) { int NbrCmp = 0; EDA_BaseStruct* DrawList = sheet->LastDrawList(); SCH_COMPONENT* DrawLibItem; EDA_LibComponentStruct* Entry; for( ; DrawList; DrawList = DrawList->Pnext ) { if( DrawList->Type() == TYPE_SCH_COMPONENT ) { DrawLibItem = (SCH_COMPONENT*) DrawList; Entry = FindLibPart( DrawLibItem->m_ChipName.GetData(), wxEmptyString, FIND_ROOT ); if( Entry == NULL ) continue; if( BaseListeCmp == NULL ) /* Items counting only */ { NbrCmp++; continue; } BaseListeCmp[NbrCmp].m_Cmp = DrawLibItem; BaseListeCmp[NbrCmp].m_NbParts = Entry->m_UnitCount; BaseListeCmp[NbrCmp].m_Unit = DrawLibItem->GetUnitSelection( sheet ); // DrawLibItem->m_Multi; BaseListeCmp[NbrCmp].m_PartsLocked = Entry->m_UnitSelectionLocked; BaseListeCmp[NbrCmp].m_SheetList = *sheet; BaseListeCmp[NbrCmp].m_IsNew = FALSE; BaseListeCmp[NbrCmp].m_Pos = DrawLibItem->m_Pos; BaseListeCmp[NbrCmp].m_TimeStamp = DrawLibItem->m_TimeStamp; if( DrawLibItem->GetRef( sheet ).IsEmpty() ) DrawLibItem->SetRef( sheet, wxT( "DefRef?" ) ); strncpy( BaseListeCmp[NbrCmp].m_TextRef, CONV_TO_UTF8( DrawLibItem->GetRef( sheet ) ), 32 ); BaseListeCmp[NbrCmp].m_NumRef = -1; if( DrawLibItem->GetField(VALUE)->m_Text.IsEmpty() ) DrawLibItem->GetField(VALUE)->m_Text = wxT( "~" ); strncpy( BaseListeCmp[NbrCmp].m_TextValue, CONV_TO_UTF8( DrawLibItem->GetField(VALUE)->m_Text ), 32 ); NbrCmp++; } } return NbrCmp; } /***************************************************************************** * Update the reference component for the schematic project (or the current * sheet) *****************************************************************************/ static void ReAnnotateComponents( CmpListStruct* BaseListeCmp, int NbOfCmp ) { int ii; char* Text; SCH_COMPONENT* DrawLibItem; /* Reattribution des numeros */ for( ii = 0; ii < NbOfCmp; ii++ ) { Text = BaseListeCmp[ii].m_TextRef; DrawLibItem = BaseListeCmp[ii].m_Cmp; if( BaseListeCmp[ii].m_NumRef < 0 ) strcat( Text, "?" ); else sprintf( Text + strlen( Text ), "%d", BaseListeCmp[ii].m_NumRef ); DrawLibItem->SetRef( &(BaseListeCmp[ii].m_SheetList), CONV_FROM_UTF8( Text ) ); DrawLibItem->m_Multi = BaseListeCmp[ii].m_Unit; DrawLibItem->SetUnitSelection( &(BaseListeCmp[ii].m_SheetList), DrawLibItem->m_Multi ); } } /***************************************************************************** * Split component reference designators into a name (prefix) and number. * Example: IC1 becomes IC and 1 in the .m_NumRef member. * For multi part per package components not already annotated, set .m_Unit * to a max value (0x7FFFFFFF). * * @param BaseListeCmp = list of component * @param NbOfCmp = item count in the list *****************************************************************************/ void BreakReference( CmpListStruct* BaseListeCmp, int NbOfCmp ) { int ii, ll; char* Text; for( ii = 0; ii < NbOfCmp; ii++ ) { BaseListeCmp[ii].m_NumRef = -1; Text = BaseListeCmp[ii].m_TextRef; ll = strlen( Text ) - 1; if( Text[ll] == '?' ) { BaseListeCmp[ii].m_IsNew = true; if( !BaseListeCmp[ii].m_PartsLocked ) BaseListeCmp[ii].m_Unit = 0x7FFFFFFF; Text[ll] = 0; continue; } if( isdigit( Text[ll] ) == 0 ) { BaseListeCmp[ii].m_IsNew = true; if( !BaseListeCmp[ii].m_PartsLocked ) BaseListeCmp[ii].m_Unit = 0x7FFFFFFF; continue; } while( ll >= 0 ) { if( (Text[ll] <= ' ' ) || isdigit( Text[ll] ) ) ll--; else { if( isdigit( Text[ll + 1] ) ) BaseListeCmp[ii].m_NumRef = atoi( &Text[ll + 1] ); Text[ll + 1] = 0; break; } } } } /***************************************************************************** * Compute the reference number for components without reference number * Compute .m_NumRef member *****************************************************************************/ static void ComputeReferenceNumber( CmpListStruct* BaseListeCmp, int NbOfCmp ) { int ii, jj, LastReferenceNumber, NumberOfUnits, Unit; const char* Text, * RefText, * ValText; CmpListStruct* ObjRef, * ObjToTest; /* Components with an invisible reference (power...) always are * re-annotated */ for( ii = 0; ii < NbOfCmp; ii++ ) { Text = BaseListeCmp[ii].m_TextRef; if( *Text == '#' ) { BaseListeCmp[ii].m_IsNew = true; BaseListeCmp[ii].m_NumRef = 0; } } ValText = RefText = ""; LastReferenceNumber = 1; for( ii = 0; ii < NbOfCmp; ii++ ) { ObjRef = &BaseListeCmp[ii]; if( BaseListeCmp[ii].m_Flag ) continue; Text = BaseListeCmp[ii].m_TextRef; if( strnicmp( RefText, Text, 32 ) != 0 ) /* Nouveau Identificateur */ { RefText = BaseListeCmp[ii].m_TextRef; LastReferenceNumber = GetLastReferenceNumber( BaseListeCmp + ii, BaseListeCmp, NbOfCmp ); } /* Annotation of one part per package components (trivial case)*/ if( BaseListeCmp[ii].m_NbParts <= 1 ) { if( BaseListeCmp[ii].m_IsNew ) { LastReferenceNumber++; BaseListeCmp[ii].m_NumRef = LastReferenceNumber; } BaseListeCmp[ii].m_Unit = 1; BaseListeCmp[ii].m_Flag = 1; BaseListeCmp[ii].m_IsNew = FALSE; continue; } /* Annotation of multi-part components ( n parts per package ) * (complex case) */ ValText = BaseListeCmp[ii].m_TextValue; NumberOfUnits = BaseListeCmp[ii].m_NbParts; if( BaseListeCmp[ii].m_IsNew ) { LastReferenceNumber++; BaseListeCmp[ii].m_NumRef = LastReferenceNumber; if( !BaseListeCmp[ii].m_PartsLocked ) BaseListeCmp[ii].m_Unit = 1; BaseListeCmp[ii].m_Flag = 1; } for( Unit = 1; Unit <= NumberOfUnits; Unit++ ) { if( BaseListeCmp[ii].m_Unit == Unit ) continue; jj = ExistUnit( BaseListeCmp + ii, Unit, BaseListeCmp, NbOfCmp ); if( jj >= 0 ) continue; /* Unit exists for this reference */ /* Search a component to annotate ( same prefix, same value) */ for( jj = ii + 1; jj < NbOfCmp; jj++ ) { ObjToTest = &BaseListeCmp[jj]; if( BaseListeCmp[jj].m_Flag ) continue; Text = BaseListeCmp[jj].m_TextRef; if( strnicmp( RefText, Text, 32 ) != 0 ) continue; // references are different Text = BaseListeCmp[jj].m_TextValue; if( strnicmp( ValText, Text, 32 ) != 0 ) continue; // values are different if( !BaseListeCmp[jj].m_IsNew ) { continue; } /* Component without reference number found, annotate it if * possible */ if( !BaseListeCmp[jj].m_PartsLocked || (BaseListeCmp[jj].m_Unit == Unit) ) { BaseListeCmp[jj].m_NumRef = BaseListeCmp[ii].m_NumRef; BaseListeCmp[jj].m_Unit = Unit; BaseListeCmp[jj].m_Flag = 1; BaseListeCmp[jj].m_IsNew = FALSE; break; } } } } } /***************************************************************************** * Search the last used (greatest) reference number in the component list * for the prefix reference given by Objet * The component list must be sorted. * * @param Objet = reference item ( Objet->m_TextRef is the search pattern) * @param BaseListeCmp = list of items * @param NbOfCmp = items count in list of items *****************************************************************************/ int GetLastReferenceNumber( CmpListStruct* Objet, CmpListStruct* BaseListeCmp, int NbOfCmp ) { CmpListStruct* LastObjet = BaseListeCmp + NbOfCmp; int LastNumber = 0; const char* RefText; RefText = Objet->m_TextRef; for( ; Objet < LastObjet; Objet++ ) { /* Nouveau Identificateur */ if( strnicmp( RefText, Objet->m_TextRef, 32 ) != 0 ) break; if( LastNumber < Objet->m_NumRef ) LastNumber = Objet->m_NumRef; } return LastNumber; } /***************************************************************************** * Search in the sorted list of components, for a given componen,t an other component * with the same reference and a given part unit. * Mainly used to manage multiple parts per package components * @param Objet = the given CmpListStruct* item to test * @param Unit = the given unit number to search * @param BaseListeCmp = list of items to examine * @param NbOfCmp = size of list * @return index in BaseListeCmp if found or -1 if not found *****************************************************************************/ static int ExistUnit( CmpListStruct* Objet, int Unit, CmpListStruct* BaseListeCmp, int NbOfCmp ) { CmpListStruct* EndList = BaseListeCmp + NbOfCmp; char* RefText, * ValText; int NumRef, ii; CmpListStruct* ItemToTest; RefText = Objet->m_TextRef; ValText = Objet->m_TextValue; NumRef = Objet->m_NumRef; for( ItemToTest = BaseListeCmp, ii = 0; ItemToTest < EndList; ItemToTest++, ii++ ) { if( Objet == ItemToTest ) // Do not compare with itself ! continue; if( ItemToTest->m_IsNew ) // Not already with an updated reference continue; if( ItemToTest->m_NumRef != NumRef ) // Not the same reference number (like 35 in R35) continue; if( strnicmp( RefText, ItemToTest->m_TextRef, 32 ) != 0 ) // Not the same reference prefix continue; if( ItemToTest->m_Unit == Unit ) // A part with the same reference and the given unit is found { return ii; } } return -1; } /***************************************************************************** * * Function CheckAnnotate * @return component count ( which are not annotated or have the same * reference (duplicates)) * @param oneSheetOnly : true = search is made only in the current sheet * false = search in whole hierarchy (usual search). * *****************************************************************************/ int CheckAnnotate( WinEDA_SchematicFrame* frame, bool oneSheetOnly ) { int ii, error, NbOfCmp; DrawSheetPath* sheet; CmpListStruct* ListeCmp = NULL; wxString Buff; wxString msg, cmpref; /* build the screen list */ EDA_SheetList SheetList( NULL ); g_RootSheet->m_AssociatedScreen->SetModify(); ii = 0; /* first pass : count composents */ if( !oneSheetOnly ) { NbOfCmp = 0; for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) NbOfCmp += ListeComposants( NULL, sheet ); } else NbOfCmp = ListeComposants( NULL, frame->GetSheet() ); if( NbOfCmp == 0 ) { return 0; } /* Second pass : create the list of components */ ListeCmp = (CmpListStruct*) MyZMalloc( NbOfCmp * sizeof(CmpListStruct) ); if( !oneSheetOnly ) { ii = 0; for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) ii += ListeComposants( ListeCmp + ii, sheet ); } else ListeComposants( ListeCmp, frame->GetSheet() ); qsort( ListeCmp, NbOfCmp, sizeof(CmpListStruct), AnnotateByValue ); /* Break full components reference in name (prefix) and number: example: * IC1 become IC, and 1 */ BreakReference( ListeCmp, NbOfCmp ); /* count not yet annotated items */ error = 0; for( ii = 0; ii < NbOfCmp - 1; ii++ ) { msg.Empty(); Buff.Empty(); if( ListeCmp[ii].m_IsNew ) { if( ListeCmp[ii].m_NumRef >= 0 ) Buff << ListeCmp[ii].m_NumRef; else Buff = wxT( "?" ); cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef ); msg.Printf( _( "item not annotated: %s%s" ), cmpref.GetData(), Buff.GetData() ); if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) ) { Buff.Printf( _( "( unit %d)" ), ListeCmp[ii].m_Unit ); msg << Buff; } DisplayError( NULL, msg ); error++; break; } // Annotate error if( MAX( ListeCmp[ii].m_NbParts, 1 ) < ListeCmp[ii].m_Unit ) { if( ListeCmp[ii].m_NumRef >= 0 ) Buff << ListeCmp[ii].m_NumRef; else Buff = wxT( "?" ); cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef ); msg.Printf( _( "Error item %s%s" ), cmpref.GetData(), Buff.GetData() ); Buff.Printf( _( " unit %d and no more than %d parts" ), ListeCmp[ii].m_Unit, ListeCmp[ii].m_NbParts ); msg << Buff; DisplayError( frame, msg ); error++; break; } } if( error ) return error; // count the duplicated elements (if all are annotated) for( ii = 0; (ii < NbOfCmp - 1) && (error < 4); ii++ ) { msg.Empty(); Buff.Empty(); if( (stricmp( ListeCmp[ii].m_TextRef, ListeCmp[ii + 1].m_TextRef ) != 0) || ( ListeCmp[ii].m_NumRef != ListeCmp[ii + 1].m_NumRef ) ) continue; /* Same reference found */ /* If same unit, error ! */ if( ListeCmp[ii].m_Unit == ListeCmp[ii + 1].m_Unit ) { if( ListeCmp[ii].m_NumRef >= 0 ) Buff << ListeCmp[ii].m_NumRef; else Buff = wxT( "?" ); cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef ); msg.Printf( _( "Multiple item %s%s" ), cmpref.GetData(), Buff.GetData() ); if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) ) { Buff.Printf( _( " (unit %d)" ), ListeCmp[ii].m_Unit ); msg << Buff; } DisplayError( frame, msg ); error++; continue; } /* Test error if units are different but number of parts per package * too hight (ex U3 ( 1 part) and we find U3B the is an error) */ if( ListeCmp[ii].m_NbParts != ListeCmp[ii + 1].m_NbParts ) { if( ListeCmp[ii].m_NumRef >= 0 ) Buff << ListeCmp[ii].m_NumRef; else Buff = wxT( "?" ); cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef ); msg.Printf( _( "Multiple item %s%s" ), cmpref.GetData(), Buff.GetData() ); if( (ListeCmp[ii].m_Unit > 0) && (ListeCmp[ii].m_Unit < 0x7FFFFFFF) ) { Buff.Printf( _( " (unit %d)" ), ListeCmp[ii].m_Unit ); msg << Buff; } DisplayError( frame, msg ); error++; } /* Error if values are different between units, for the same reference */ if( stricmp( ListeCmp[ii].m_TextValue, ListeCmp[ii + 1].m_TextValue ) != 0 ) { wxString nextcmpref, cmpvalue, nextcmpvalue; cmpref = CONV_FROM_UTF8( ListeCmp[ii].m_TextRef ); nextcmpref = CONV_FROM_UTF8( ListeCmp[ii + 1].m_TextRef ); cmpvalue = CONV_FROM_UTF8( ListeCmp[ii].m_TextValue ); nextcmpvalue = CONV_FROM_UTF8( ListeCmp[ii + 1].m_TextValue ); msg.Printf( _( "Diff values for %s%d%c (%s) and %s%d%c (%s)" ), cmpref.GetData(), ListeCmp[ii].m_NumRef, ListeCmp[ii].m_Unit + 'A' - 1, cmpvalue.GetData(), nextcmpref.GetData(), ListeCmp[ii + 1].m_NumRef, ListeCmp[ii + 1].m_Unit + 'A' - 1, nextcmpvalue.GetData() ); DisplayError( frame, msg ); error++; } } MyFree( ListeCmp ); return error; }