/** @file
Function prototypes and defines for string routines.
Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include 
#include 
#include "StringFuncs.h"
//
// Functions implementations
//
CHAR8*
CloneString (
  IN CHAR8       *String
  )
/*++
Routine Description:
  Allocates a new string and copies 'String' to clone it
Arguments:
  String          The string to clone
Returns:
  CHAR8* - NULL if there are not enough resources
--*/
{
  CHAR8* NewString;
  NewString = malloc (strlen (String) + 1);
  if (NewString != NULL) {
    strcpy (NewString, String);
  }
  return NewString;
}
EFI_STATUS
StripInfDscStringInPlace (
  IN CHAR8       *String
  )
/*++
Routine Description:
  Remove all comments, leading and trailing whitespace from the string.
Arguments:
  String          The string to 'strip'
Returns:
  EFI_STATUS
--*/
{
  CHAR8 *Pos;
  if (String == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Remove leading whitespace
  //
  for (Pos = String; isspace ((int)*Pos); Pos++) {
  }
  if (Pos != String) {
    memmove (String, Pos, strlen (Pos) + 1);
  }
  //
  // Comment BUGBUGs!
  //
  // What about strings?  Comment characters are okay in strings.
  // What about multiline comments?
  //
  Pos = (CHAR8 *) strstr (String,  "//");
  if (Pos != NULL) {
    *Pos = '\0';
  }
  Pos = (CHAR8 *) strchr (String, '#');
  if (Pos != NULL) {
    *Pos = '\0';
  }
  //
  // Remove trailing whitespace
  //
  for (Pos = String + strlen (String);
       ((Pos - 1) >= String) && (isspace ((int)*(Pos - 1)));
       Pos--
      ) {
  }
  *Pos = '\0';
  return EFI_SUCCESS;
}
STRING_LIST*
SplitStringByWhitespace (
  IN CHAR8       *String
  )
/*++
Routine Description:
  Creates and returns a 'split' STRING_LIST by splitting the string
  on whitespace boundaries.
Arguments:
  String          The string to 'split'
Returns:
  EFI_STATUS
--*/
{
  CHAR8       *Pos;
  CHAR8       *EndOfSubString;
  CHAR8       *EndOfString;
  STRING_LIST *Output;
  UINTN       Item;
  String = CloneString (String);
  if (String == NULL) {
    return NULL;
  }
  EndOfString = String + strlen (String);
  Output = NewStringList ();
  for (Pos = String, Item = 0; Pos < EndOfString; Item++) {
    while (isspace ((int)*Pos)) {
      Pos++;
    }
    for (EndOfSubString=Pos;
         (*EndOfSubString != '\0') && !isspace ((int)*EndOfSubString);
         EndOfSubString++
         ) {
    }
    if (EndOfSubString == Pos) {
      break;
    }
    *EndOfSubString = '\0';
    AppendCopyOfStringToList (&Output, Pos);
    Pos = EndOfSubString + 1;
  }
  free (String);
  return Output;
}
STRING_LIST*
NewStringList (
  )
/*++
Routine Description:
  Creates a new STRING_LIST with 0 strings.
Returns:
  STRING_LIST* - Null if there is not enough resources to create the object.
--*/
{
  STRING_LIST *NewList;
  NewList = AllocateStringListStruct (0);
  if (NewList != NULL) {
    NewList->Count = 0;
  }
  return NewList;
}
EFI_STATUS
AppendCopyOfStringToList (
  IN OUT STRING_LIST **StringList,
  IN CHAR8       *String
  )
/*++
Routine Description:
  Adds String to StringList.  A new copy of String is made before it is
  added to StringList.
Returns:
  EFI_STATUS
--*/
{
  STRING_LIST *OldList;
  STRING_LIST *NewList;
  CHAR8       *NewString;
  OldList = *StringList;
  NewList = AllocateStringListStruct (OldList->Count + 1);
  if (NewList == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  NewString = CloneString (String);
  if (NewString == NULL) {
    free (NewList);
    return EFI_OUT_OF_RESOURCES;
  }
  memcpy (
    NewList->Strings,
    OldList->Strings,
    sizeof (OldList->Strings[0]) * OldList->Count
    );
  NewList->Count = OldList->Count + 1;
  NewList->Strings[OldList->Count] = NewString;
  *StringList = NewList;
  free (OldList);
  return EFI_SUCCESS;
}
EFI_STATUS
RemoveLastStringFromList (
  IN STRING_LIST       *StringList
  )
/*++
Routine Description:
  Removes the last string from StringList and frees the memory associated
  with it.
Arguments:
  StringList        The string list to remove the string from
Returns:
  EFI_STATUS
--*/
{
  if (StringList->Count == 0) {
    return EFI_INVALID_PARAMETER;
  }
  free (StringList->Strings[StringList->Count - 1]);
  StringList->Count--;
  return EFI_SUCCESS;
}
STRING_LIST*
AllocateStringListStruct (
  IN UINTN StringCount
  )
/*++
Routine Description:
  Allocates a STRING_LIST structure that can store StringCount strings.
Arguments:
  StringCount        The number of strings that need to be stored
Returns:
  EFI_STATUS
--*/
{
  return malloc (OFFSET_OF(STRING_LIST, Strings[StringCount + 1]));
}
VOID
FreeStringList (
  IN STRING_LIST       *StringList
  )
/*++
Routine Description:
  Frees all memory associated with StringList.
Arguments:
  StringList        The string list to free
Returns:
  VOID
--*/
{
  while (StringList->Count > 0) {
    RemoveLastStringFromList (StringList);
  }
  free (StringList);
}
CHAR8*
StringListToString (
  IN STRING_LIST       *StringList
  )
/*++
Routine Description:
  Generates a string that represents the STRING_LIST
Arguments:
  StringList        The string list to convert to a string
Returns:
  CHAR8* - The string list represented with a single string.  The returned
           string must be freed by the caller.
--*/
{
  UINTN Count;
  UINTN Length;
  CHAR8 *NewString;
  Length = 2;
  for (Count = 0; Count < StringList->Count; Count++) {
    if (Count > 0) {
      Length += 2;
    }
    Length += strlen (StringList->Strings[Count]) + 2;
  }
  NewString = malloc (Length + 1);
  if (NewString == NULL) {
    return NewString;
  }
  NewString[0] = '\0';
  strcat (NewString, "[");
  for (Count = 0; Count < StringList->Count; Count++) {
    if (Count > 0) {
      strcat (NewString, ", ");
    }
    strcat (NewString, "\"");
    strcat (NewString, StringList->Strings[Count]);
    strcat (NewString, "\"");
  }
  strcat (NewString, "]");
  return NewString;
}
VOID
PrintStringList (
  IN STRING_LIST       *StringList
  )
/*++
Routine Description:
  Prints out the string list
Arguments:
  StringList        The string list to print
Returns:
  EFI_STATUS
--*/
{
  CHAR8* String;
  String = StringListToString (StringList);
  if (String != NULL) {
    printf ("%s", String);
    free (String);
  }
}