diff --git a/cinera/cinera.c b/cinera/cinera.c index 412ff93..c833edd 100644 --- a/cinera/cinera.c +++ b/cinera/cinera.c @@ -23,7 +23,7 @@ typedef struct version CINERA_APP_VERSION = { .Major = 0, .Minor = 10, - .Patch = 15 + .Patch = 16 }; #define __USE_XOPEN2K8 // NOTE(matt): O_NOFOLLOW @@ -971,6 +971,17 @@ StringContains(string S, string Substring) return Result; } +int +StringContainsXOfChar(string S, char C) +{ + int Result = 0; + for(int i = 0; i < S.Length; ++i) + { + Result += S.Base[i] == C; + } + return Result; +} + bool StringsMatchCaseInsensitive(string A, string B) { @@ -1413,6 +1424,9 @@ typedef struct config_identifier ConfigIdentifiers[] = { { "" }, + { "abbrev_dotted_initial_and_surname", "The dotted-initial(s) and surname of a person's name, used to override the auto-derived one, e.g. J. R. R. Tolkien (from John Ronald Reuel Tolkien) or J. du Pré (from Jacqueline du Pré)" }, + { "abbrev_given_or_nickname", "The given or quoted nickname of a person's name, used to override the auto-derived one, e.g. Charlotte (from Charlotte Brontë) or Ry (from Ryland Peter \"Ry\" Cooder)" }, + { "abbrev_initial", "The initials of a person's name, used to override the auto-derived ones, e.g. KB (from Kate Bush)" }, { "allow", "An include-rule string of the forms: \"identifier\", \"type.member\" or \"type.member.member\", etc. For example:\n\nallow = \"project.default_medium\";\n\nAdding an \"allow\" / \"deny\" rule makes the inclusion prohibitive or permissive, respectively, \ and they cannot be mixed (i.e. only \"allow\" rules, or only \"deny\" rules)." @@ -1557,6 +1571,9 @@ fill the slots left vacant by positioned roles in the order in which they are co typedef enum { IDENT_NULL, + IDENT_ABBREV_DOTTED_INITIAL_AND_SURNAME, + IDENT_ABBREV_GIVEN_OR_NICKNAME, + IDENT_ABBREV_INITIAL, IDENT_ALLOW, IDENT_ART, IDENT_ART_VARIANTS, @@ -1944,6 +1961,22 @@ ConfigError(string *Filename, uint64_t LineNumber, severity Severity, char *Mess fprintf(stderr, "\n"); } +void +ConfigErrorField(string *Filename, uint64_t LineNumber, severity Severity, config_identifier_id FieldID, + char *Message, string *Received) +{ + ErrorFilenameAndLineNumber(Filename, LineNumber, Severity, ED_CONFIG); + fprintf(stderr, + "Faulty %s%s%s %s", + ColourStrings[CS_YELLOW_BOLD], ConfigIdentifiers[FieldID].String, ColourStrings[CS_END], + Message); + if(Received) + { + PrintStringC(CS_MAGENTA_BOLD, *Received); + } + fprintf(stderr, "\n"); +} + void ConfigErrorUnset(config_identifier_id FieldID) { @@ -1952,6 +1985,19 @@ ConfigErrorUnset(config_identifier_id FieldID) "Unset %s\n", ConfigIdentifiers[FieldID].String); } +void +ConfigErrorUnsetFieldOf(string *Filename, uint64_t LineNumber, + config_identifier_id UnsetFieldID, + config_identifier_id ScopeKey, string ScopeID) +{ + ErrorFilenameAndLineNumber(Filename, LineNumber, S_ERROR, ED_CONFIG); + fprintf(stderr, + "Unset %s%s%s of %s%s%s: %s%.*s%s\n", + ColourStrings[CS_YELLOW_BOLD], ConfigIdentifiers[UnsetFieldID].String, ColourStrings[CS_END], + ColourStrings[CS_YELLOW_BOLD], ConfigIdentifiers[ScopeKey].String, ColourStrings[CS_END], + ColourStrings[CS_GREEN_BOLD], (int)ScopeID.Length, ScopeID.Base, ColourStrings[CS_END]); +} + void ConfigErrorSizing(string *Filename, uint64_t LineNumber, config_identifier_id FieldID, string *Received, uint64_t MaxSize) { @@ -5091,14 +5137,13 @@ typedef struct { hsl_colour Colour; person *Person; - string Abbreviation; bool Seen; } speaker; typedef struct { _memory_book(speaker) Speakers; - memory_book Abbreviations; + abbreviation_scheme AbbrevScheme; } speakers; enum @@ -6837,94 +6882,38 @@ ConstructResolvedAssetURL(buffer *Buffer, asset *Asset, page_type PageType) Free(ResolvablePath); } -string -InitialString(memory_book *Abbreviations, string Src) +void +PickAbbreviationScheme(speakers *Speakers) { - ResetPen(Abbreviations); - string Result = {}; - string Char = Wrap0i_(Src.Base, 1); - - Result = ExtendStringInBook(Abbreviations, Char); - for(int i = 1; i < Src.Length; ++i) + Speakers->AbbrevScheme = AS_NONE; + int SchemeCount = 3; + for(int SchemeIndex = 0; SchemeIndex < SchemeCount; ++SchemeIndex) { - if(Src.Base[i] == ' ' && i < Src.Length) + bool Clash = FALSE; + for(int i = 0; i < Speakers->Speakers.ItemCount; ++i) { - ++i; - Char = Wrap0i_(Src.Base + i, 1); - Result = ExtendStringInBook(Abbreviations, Char); - } - } - return Result; -} - -string -GetFirstSubstring(string Src) -{ - string Result = Src; - for(Result.Length = 0; Result.Length < Src.Length && Result.Base[Result.Length] != ' '; ++Result.Length) { } - return Result; -} - -string -InitialAndGetFinalString(memory_book *Abbreviations, string Src) -{ - ResetPen(Abbreviations); - string Result = {}; - int FinalStringBase; - for(FinalStringBase = Src.Length; FinalStringBase > 0; --FinalStringBase) - { - if(Src.Base[FinalStringBase - 1] == ' ') { break; } - } - - if(FinalStringBase > 0 && Src.Base[FinalStringBase] == ' ' && FinalStringBase < Src.Length) - { - ++FinalStringBase; - } - - string FinalString = Wrap0i_(Src.Base + FinalStringBase, Src.Length - FinalStringBase); - - if(FinalStringBase > 0) - { - string Initial = Wrap0i_(Src.Base, 1); - Result = ExtendStringInBook(Abbreviations, Initial); - Result = ExtendStringInBook(Abbreviations, Wrap0(". ")); - - for(int i = 0; i < FinalStringBase; ++i) - { - if(Src.Base[i] == ' ' && i + 1 < FinalStringBase) + speaker *A = GetPlaceInBook(&Speakers->Speakers, i); + for(int j = i + 1; j < Speakers->Speakers.ItemCount; ++j) { - ++i; - string Initial = Wrap0i_(Src.Base + i, 1); - Result = ExtendStringInBook(Abbreviations, Initial); - Result = ExtendStringInBook(Abbreviations, Wrap0(". ")); + speaker *B = GetPlaceInBook(&Speakers->Speakers, j); + if(StringsMatch(A->Person->Abbreviations[SchemeIndex], B->Person->Abbreviations[SchemeIndex])) + { + Clash = TRUE; + break; + } } + if(Clash) { break; } } - } - - Result = ExtendStringInBook(Abbreviations, FinalString); - return Result; -} - -bool -AbbreviationsClash(memory_book *Speakers) -{ - for(int i = 0; i < Speakers->ItemCount; ++i) - { - speaker *A = GetPlaceInBook(Speakers, i); - for(int j = i + 1; j < Speakers->ItemCount; ++j) + if(!Clash) { - speaker *B = GetPlaceInBook(Speakers, j); - if(StringsMatch(A->Abbreviation, B->Abbreviation)) - { - return TRUE; - } + Speakers->AbbrevScheme = SchemeIndex; + break; } } - return FALSE; } void -SortAndAbbreviateSpeakers(speakers *Speakers) +SortSpeakersAndPickAbbreviationScheme(speakers *Speakers) { for(int i = 0; i < Speakers->Speakers.ItemCount; ++i) { @@ -6945,26 +6934,10 @@ SortAndAbbreviateSpeakers(speakers *Speakers) for(int i = 0; i < Speakers->Speakers.ItemCount; ++i) { speaker *This = GetPlaceInBook(&Speakers->Speakers, i); - string Name = This->Person->Name.Length > 0 ? This->Person->Name : This->Person->ID; StringToColourHash(&This->Colour, This->Person->ID); - This->Abbreviation = InitialString(&Speakers->Abbreviations, Name); } - int MaxAttemptCount = 3; - for(int Attempt = 0; Attempt < MaxAttemptCount && AbbreviationsClash(&Speakers->Speakers); ++Attempt) - { - for(int i = 0; i < Speakers->Speakers.ItemCount; ++i) - { - speaker *This = GetPlaceInBook(&Speakers->Speakers, i); - string Name = This->Person->Name.Length > 0 ? This->Person->Name : This->Person->ID; - switch(Attempt) - { - case 0: This->Abbreviation = GetFirstSubstring(Name); break; - case 1: This->Abbreviation = InitialAndGetFinalString(&Speakers->Abbreviations, Name); break; - case 2: This->Abbreviation = Name; break; - } - } - } + PickAbbreviationScheme(Speakers); } person * @@ -7359,7 +7332,6 @@ void FreeSpeakers(speakers *Speakers) { FreeBook(&Speakers->Speakers); - FreeBook(&Speakers->Abbreviations); } void @@ -7644,11 +7616,11 @@ BuildCredits(string HMMLFilepath, buffer *CreditsMenu, HMML_VideoMetaData *Metad } FreeBook(&Credits); - // NOTE(matt): As we only cite the speaker when there are a multiple of them, we only need to SortAndAbbreviateSpeakers() - // in the same situation + // NOTE(matt): As we only cite the speaker when there are a multiple of them, we only + // need to SortSpeakersAndPickAbbreviationScheme() in the same situation if(Speakers->Speakers.ItemCount > 1) { - SortAndAbbreviateSpeakers(Speakers); + SortSpeakersAndPickAbbreviationScheme(Speakers); } if(CreditsMenu->Ptr > CreditsMenu->Location) @@ -10093,7 +10065,6 @@ InitSpeakers() { speakers Result = {}; Result.Speakers = InitBook(sizeof(speaker), 4); - Result.Abbreviations = InitBookOfStrings(64); return Result; } @@ -10385,14 +10356,22 @@ ProcessTimestamp(buffers *CollationBuffers, neighbourhood *N, string Filepath, m // NOTE(matt): I reckon it's fair to only cite the speaker when there are a multiple of them if(Speakers->Speakers.ItemCount > 1 && Speaker && !IsCategorisedAuthored(Timestamp)) { - string DisplayName = !Speaker->Seen ? Speaker->Person->Name : Speaker->Abbreviation; + string DisplayName = !Speaker->Seen ? Speaker->Person->Name : Speaker->Person->Abbreviations[Speakers->AbbrevScheme]; CopyStringToBuffer(&IndexBuffers->Text, - "%.*s: ", + "Colour.Hue, - Speaker->Colour.Saturation, + Speaker->Colour.Saturation); - (int)DisplayName.Length, DisplayName.Base); + if(Speaker->Seen) + { + CopyStringToBuffer(&IndexBuffers->Text, " title=\""); + CopyStringToBufferHTMLSafe(&IndexBuffers->Text, Speaker->Person->Name); + CopyStringToBuffer(&IndexBuffers->Text, "\""); + } + + CopyStringToBuffer(&IndexBuffers->Text, + ">%.*s: ", (int)DisplayName.Length, DisplayName.Base); Speaker->Seen = TRUE; } @@ -16084,7 +16063,6 @@ InsertProjectIntoDB(project_generations *G, db_block_projects **Block, db_header uint64_t Byte = 0; OpenFileForWriting(&DB.Metadata.File); - WriteFromByteToPointer(&DB.Metadata.File, &Byte, *Block); uint64_t PPos; if(GotBlock) @@ -17258,11 +17236,8 @@ MonitorFilesystem(neighbourhood *N, buffers *CollationBuffers, template *Bespoke } break; case WT_CONFIG: { - if(Config) - { - DiscardAllAndFreeConfig(); - PushWatchHandle(ConfigPath, EXT_NULL, WT_CONFIG, 0, 0); - } + DiscardAllAndFreeConfig(); + PushWatchHandle(ConfigPath, EXT_NULL, WT_CONFIG, 0, 0); ParseAndEitherPrintConfigOrInitAll(ConfigPath, TokensList, N, CollationBuffers, BespokeTemplate); } break; @@ -17400,7 +17375,7 @@ main(int ArgC, char **Args) if(ClaimBuffer(&CollationBuffers.IncludesPlayer, BID_COLLATION_BUFFERS_INCLUDES_PLAYER, Kilobytes(2)) == RC_ARENA_FULL) { Exit(); }; if(ClaimBuffer(&CollationBuffers.Player, BID_COLLATION_BUFFERS_PLAYER, Kilobytes(552)) == RC_ARENA_FULL) { Exit(); }; - if(ClaimBuffer(&CollationBuffers.IncludesSearch, BID_COLLATION_BUFFERS_INCLUDES_SEARCH, Kilobytes(2)) == RC_ARENA_FULL) { Exit(); }; + if(ClaimBuffer(&CollationBuffers.IncludesSearch, BID_COLLATION_BUFFERS_INCLUDES_SEARCH, Kilobytes(4)) == RC_ARENA_FULL) { Exit(); }; if(ClaimBuffer(&CollationBuffers.SearchEntry, BID_COLLATION_BUFFERS_SEARCH_ENTRY, Kilobytes(32)) == RC_ARENA_FULL) { Exit(); }; CollationBuffers.Search.ID = BID_COLLATION_BUFFERS_SEARCH; // NOTE(matt): Allocated by SearchToBuffer() diff --git a/cinera/cinera_config.c b/cinera/cinera_config.c index 0c551fa..2b765aa 100644 --- a/cinera/cinera_config.c +++ b/cinera/cinera_config.c @@ -480,11 +480,21 @@ typedef struct bool Hidden; } medium; +typedef enum +{ + AS_INITIAL, + AS_GIVEN_OR_NICKNAME, + AS_DOTTED_INITIAL_AND_SURNAME, + AS_NONE, + AS_COUNT +} abbreviation_scheme; + typedef struct { string ID; string Name; // TODO(matt): string SortName; + string Abbreviations[AS_COUNT]; string QuoteUsername; string Homepage; _memory_book(support) Support; @@ -979,6 +989,9 @@ InitTypeSpecs(void) config_type_spec *Person = PushTypeSpec(&Result, IDENT_PERSON, FALSE); PushTypeSpecField(Person, FT_STRING, IDENT_NAME, TRUE); + PushTypeSpecField(Person, FT_STRING, IDENT_ABBREV_INITIAL, TRUE); + PushTypeSpecField(Person, FT_STRING, IDENT_ABBREV_GIVEN_OR_NICKNAME, TRUE); + PushTypeSpecField(Person, FT_STRING, IDENT_ABBREV_DOTTED_INITIAL_AND_SURNAME, TRUE); PushTypeSpecField(Person, FT_STRING, IDENT_HOMEPAGE, TRUE); PushTypeSpecField(Person, FT_STRING, IDENT_QUOTE_USERNAME, TRUE); PushTypeSpecField(Person, FT_SCOPE, IDENT_SUPPORT, FALSE); @@ -3231,6 +3244,230 @@ PushSupport(config *C, resolution_errors *E, config_verifiers *V, person *P, sco } } +void +InitialSubstring(memory_book *Abbreviations, + string *Dest, string Src, int Extent, string PostInitialString) +{ + int SrcIndex = 0; + bool InQuote = FALSE; + string Initial; + int StepSize = 1; + if(Src.Base[SrcIndex] == '\"') + { + InQuote = !InQuote; + } + else + { + Initial = GetUTF8Character(Src.Base + SrcIndex, Extent - SrcIndex); + *Dest = ExtendStringInBook(Abbreviations, Initial); + *Dest = ExtendStringInBook(Abbreviations, PostInitialString); + StepSize = Initial.Length; + } + SrcIndex += StepSize; + + for(; SrcIndex < Extent; SrcIndex += StepSize) + { + StepSize = 1; + switch(Src.Base[SrcIndex]) + { + case ' ': + { + if(!InQuote + && SrcIndex + 1 < Extent && Src.Base[SrcIndex + 1] != '\"') + { + Initial = GetUTF8Character(Src.Base + SrcIndex + 1, Extent - SrcIndex - 1); + *Dest = ExtendStringInBook(Abbreviations, Initial); + *Dest = ExtendStringInBook(Abbreviations, PostInitialString); + StepSize = Initial.Length; + } + } break; + case '\"': + { + InQuote = !InQuote; + } break; + } + } +} + +string +InitialString(memory_book *Abbreviations, string Src) +{ + ResetPen(Abbreviations); + string Result = {}; + InitialSubstring(Abbreviations, &Result, Src, Src.Length, Wrap0("")); + return Result; +} + +string +GetQuotedOrFirstSubstring(string Src) +{ + string Result; + + string QuotedSubstring = {}; + string FirstSubstring = Src; + bool GotFirstSubstring = FALSE; + bool InQuote = FALSE; + + for(int SrcIndex = 0; SrcIndex < Src.Length && !QuotedSubstring.Length; ++SrcIndex) + { + switch(Src.Base[SrcIndex]) + { + case ' ': + { + if(!InQuote && !GotFirstSubstring) + { + FirstSubstring.Base = Src.Base; + FirstSubstring.Length = SrcIndex; + GotFirstSubstring = TRUE; + } + } break; + case '\"': + { + if(!InQuote) + { + if(SrcIndex + 1 < Src.Length) + { + QuotedSubstring.Base = Src.Base + SrcIndex + 1; + } + } + else + { + QuotedSubstring.Length = SrcIndex - (QuotedSubstring.Base - Src.Base); + } + InQuote = !InQuote; + } break; + } + } + + Result = QuotedSubstring.Length ? QuotedSubstring : FirstSubstring; + return Result; +} + +string +StripQuotedStringStart(string S) +{ + string Result = S; + if(Result.Length > 0 && Result.Base[0] == '\"') + { + ++Result.Base; + --Result.Length; + while(Result.Length > 0 && Result.Base[0] != '\"') + { + ++Result.Base; + --Result.Length; + } + Assert(Result.Length > 0); + ++Result.Base; + --Result.Length; + } + return Result; +} + +string +StripQuotedStringEnd(string S) +{ + string Result = S; + if(Result.Length > 0 && Result.Base[Result.Length - 1] == '\"') + { + --Result.Length; + while(Result.Length > 0 && Result.Base[Result.Length - 1] != '\"') + { + --Result.Length; + } + Assert(Result.Length > 0); + --Result.Length; + } + return Result; +} + +bool +IsLower(char C) +{ + return C >= 'a' && C <= 'z'; +} + +string +DottedInitialAndGetSurname(memory_book *Abbreviations, string Src) +{ + ResetPen(Abbreviations); + string Result = {}; + bool GotSurnameBase = FALSE; + string WorkingSrc = Src; + + WorkingSrc = StripQuotedStringStart(WorkingSrc); + WorkingSrc = StripQuotedStringEnd(WorkingSrc); + WorkingSrc = TrimWhitespace(WorkingSrc); + + int PossibleSurnameBase = WorkingSrc.Length - 1; + int SurnameBase = PossibleSurnameBase; + + for(; PossibleSurnameBase > 0; --PossibleSurnameBase) + { + char Prev = WorkingSrc.Base[PossibleSurnameBase - 1]; + if(Prev == ' ') + { + if(!GotSurnameBase) + { + SurnameBase = PossibleSurnameBase; + } + else if(IsLower(WorkingSrc.Base[PossibleSurnameBase])) + { + SurnameBase = PossibleSurnameBase; + } + else + { + break; + } + GotSurnameBase = TRUE; + } + else if(Prev == '\"') + { + break; + } + } + + if(!GotSurnameBase) + { + SurnameBase = PossibleSurnameBase; + } + + if(SurnameBase > 0 && WorkingSrc.Base[SurnameBase] == ' ' && SurnameBase < WorkingSrc.Length) + { + ++SurnameBase; + } + + string Surname = Wrap0i_(WorkingSrc.Base + SurnameBase, WorkingSrc.Length - SurnameBase); + + if(SurnameBase > 0) + { + InitialSubstring(Abbreviations, &Result, WorkingSrc, SurnameBase, Wrap0(". ")); + } + + Result = ExtendStringInBook(Abbreviations, Surname); + return Result; +} + +void +AbbreviateName(config *C, person *P) +{ + if(P->Abbreviations[AS_INITIAL].Length == 0) + { + P->Abbreviations[AS_INITIAL] = InitialString(&C->ResolvedVariables, P->Name); + } + + if(P->Abbreviations[AS_GIVEN_OR_NICKNAME].Length == 0) + { + P->Abbreviations[AS_GIVEN_OR_NICKNAME] = GetQuotedOrFirstSubstring(P->Name); + } + + if(P->Abbreviations[AS_DOTTED_INITIAL_AND_SURNAME].Length == 0) + { + P->Abbreviations[AS_DOTTED_INITIAL_AND_SURNAME] = DottedInitialAndGetSurname(&C->ResolvedVariables, P->Name); + } + + P->Abbreviations[AS_NONE] = P->Name; +} + void PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope_tree *PersonTree) { @@ -3238,12 +3475,30 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope //PrintScopeTree(PersonTree); person *This = MakeSpaceInBook(&C->Person); This->ID = ResolveString(C, E, PersonTree, &PersonTree->ID, FALSE); + bool NamingError = FALSE; for(int i = 0; i < PersonTree->Pairs.ItemCount; ++i) { config_pair *Pair = GetPlaceInBook(&PersonTree->Pairs, i); if(IDENT_NAME == Pair->Key) { This->Name = ResolveString(C, E, PersonTree, Pair, FALSE); + int QuotemarkCount = StringContainsXOfChar(This->Name, '\"'); + if(QuotemarkCount == 1) + { + string Filepath = Wrap0(Pair->Position.Filename); + ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME, + "contains unpaired quotation mark: ", &This->Name); + PushError(E, S_ERROR, 0, Pair->Key); + NamingError = TRUE; + } + else if(QuotemarkCount > 2) + { + string Filepath = Wrap0(Pair->Position.Filename); + ConfigErrorField(&Filepath, Pair->Position.LineNumber, S_ERROR, IDENT_NAME, + "contains more than one pair of quotation marks: ", &This->Name); + PushError(E, S_ERROR, 0, Pair->Key); + NamingError = TRUE; + } } else if(IDENT_HOMEPAGE == Pair->Key) { @@ -3255,6 +3510,20 @@ PushPersonOntoConfig(config *C, resolution_errors *E, config_verifiers *V, scope } } + if(This->Name.Length == 0) + { + string Filepath = Wrap0(PersonTree->ID.Position.Filename); + ConfigErrorUnsetFieldOf(&Filepath, PersonTree->ID.Position.LineNumber, + IDENT_NAME, IDENT_PERSON, This->ID); + PushError(E, S_ERROR, 0, IDENT_NAME); + NamingError = TRUE; + } + + if(!NamingError) + { + AbbreviateName(C, This); + } + if(This->QuoteUsername.Length == 0) { This->QuoteUsername = This->ID; @@ -4113,6 +4382,9 @@ GetRowsRequiredForPersonInfo(typography *T, person *P) uint8_t RowsRequired = 0; if(P->Name.Length > 0) { ++RowsRequired; } + if(P->Abbreviations[AS_INITIAL].Length > 0) { ++RowsRequired; } + if(P->Abbreviations[AS_GIVEN_OR_NICKNAME].Length > 0) { ++RowsRequired; } + if(P->Abbreviations[AS_DOTTED_INITIAL_AND_SURNAME].Length > 0) { ++RowsRequired; } if(P->Homepage.Length > 0) { ++RowsRequired; } for(int i = 0; i < P->Support.ItemCount; ++i) { @@ -4150,6 +4422,27 @@ PrintPerson(person *P, typography *Typography) --RowsRequired; } + if(P->Abbreviations[AS_INITIAL].Length > 0) + { + fprintf(stderr, "%s ", RowsRequired == 1 ? Typography->LowerLeft : Typography->Vertical); + config_pair AbbrevInitial = { .Key = IDENT_ABBREV_INITIAL, .String = P->Abbreviations[AS_INITIAL], .Type = PT_STRING }; PrintPair(&AbbrevInitial, Typography->Delimiter, ShouldFillSyntax, IndentationLevel, FALSE, TRUE); + --RowsRequired; + } + + if(P->Abbreviations[AS_GIVEN_OR_NICKNAME].Length > 0) + { + fprintf(stderr, "%s ", RowsRequired == 1 ? Typography->LowerLeft : Typography->Vertical); + config_pair AbbrevGivenOrNickname = { .Key = IDENT_ABBREV_GIVEN_OR_NICKNAME, .String = P->Abbreviations[AS_GIVEN_OR_NICKNAME], .Type = PT_STRING }; PrintPair(&AbbrevGivenOrNickname, Typography->Delimiter, ShouldFillSyntax, IndentationLevel, FALSE, TRUE); + --RowsRequired; + } + + if(P->Abbreviations[AS_DOTTED_INITIAL_AND_SURNAME].Length > 0) + { + fprintf(stderr, "%s ", RowsRequired == 1 ? Typography->LowerLeft : Typography->Vertical); + config_pair AbbrevDottedInitialAndSurname = { .Key = IDENT_ABBREV_DOTTED_INITIAL_AND_SURNAME, .String = P->Abbreviations[AS_DOTTED_INITIAL_AND_SURNAME], .Type = PT_STRING }; PrintPair(&AbbrevDottedInitialAndSurname, Typography->Delimiter, ShouldFillSyntax, IndentationLevel, FALSE, TRUE); + --RowsRequired; + } + if(P->Homepage.Length > 0) { fprintf(stderr, "%s ", RowsRequired == 1 ? Typography->LowerLeft : Typography->Vertical);