#include <petsc/private/petscimpl.h>
#include <petsc/private/bagimpl.h> /*I  "petscbag.h"   I*/
#include <petscviewer.h>

/*
      Adds item to the linked list in a bag
*/
static PetscErrorCode PetscBagRegister_Private(PetscBag bag, PetscBagItem item, const char *name, const char *help)
{
  PetscFunctionBegin;
  PetscCall(PetscStrncpy(item->name, name, PETSC_BAG_NAME_LENGTH - 1));
  PetscCall(PetscStrncpy(item->help, help, PETSC_BAG_HELP_LENGTH - 1));
  if (bag->bagitems) {
    PetscBagItem nitem = bag->bagitems;

    while (nitem->next) nitem = nitem->next;
    nitem->next = item;
  } else bag->bagitems = item;
  bag->count++;
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterEnum - add an enum value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of enum in struct, for example `&params->dt`
. list     - array of strings containing names of enum values followed by enum name followed by enum prefix
. mdefault - the initial value, cast with (`PetscEnum`)
. name     - the name of the item
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`
@*/
PetscErrorCode PetscBagRegisterEnum(PetscBag bag, void *addr, const char *const *list, PetscEnum mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;
  PetscInt     i = 0;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(list, 3);
  PetscAssertPointer(name, 5);
  PetscAssertPointer(help, 6);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) {
    while (list[i++]);
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: (%s) %s (choose one of) ", bag->bagprefix ? bag->bagprefix : "", name, list[mdefault], list[i - 3], help));
    for (i = 0; list[i + 2]; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, " %s", list[i]));
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, "\n"));
  }
  PetscCall(PetscOptionsGetEnum(NULL, bag->bagprefix, nname, list, &mdefault, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_ENUM;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next  = NULL;
  item->msize = 1;
  PetscCall(PetscStrArrayallocpy(list, &item->list));
  *(PetscEnum *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterIntArray - add a `PetscInt` array to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag   - the bag of values
. addr  - location of integer in struct, for example `&params->i`
. msize - number of entries in array
. name  - name of the array
- help  - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterIntArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;
  PetscInt     i, tmp = msize;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) {
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
    for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%" PetscInt_FMT " ", *((PetscInt *)addr) + i));
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
  }
  PetscCall(PetscOptionsGetIntArray(NULL, bag->bagprefix, nname, (PetscInt *)addr, &tmp, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_INT;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next  = NULL;
  item->msize = msize;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterRealArray - add a `PetscReal` array to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag   - the bag of values
. addr  - location of real array in struct, for example `&params->d`
. msize - number of entries in the array
. name  - name of the array
- help  - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterRealArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;
  PetscInt     i, tmp = msize;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) {
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
    for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%g ", (double)(*((PetscReal *)addr) + i)));
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
  }
  PetscCall(PetscOptionsGetRealArray(NULL, bag->bagprefix, nname, (PetscReal *)addr, &tmp, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_REAL;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next  = NULL;
  item->msize = msize;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterInt - add a `PetscInt` value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of integer in struct, for example `&params->i`
. mdefault - the initial value
. name     - name of the integer
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt64()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterInt(PetscBag bag, void *addr, PetscInt mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%" PetscInt_FMT ">: %s \n", bag->bagprefix ? bag->bagprefix : "", name, mdefault, help));
  PetscCall(PetscOptionsGetInt(NULL, bag->bagprefix, nname, &mdefault, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_INT;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next        = NULL;
  item->msize       = 1;
  *(PetscInt *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterInt64 - add a `PetscInt64` value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of integer in struct, for example `&params->i`
. mdefault - the initial value
. name     - name of the integer
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterInt64(PetscBag bag, void *addr, PetscInt64 mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;
  PetscInt     odefault;
  PetscBool    flg;

  PetscFunctionBegin;
  nname[0] = '-';
  nname[1] = 0;

  PetscCall(PetscIntCast(mdefault, &odefault));
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%" PetscInt_FMT ">: %s \n", bag->bagprefix ? bag->bagprefix : "", name, odefault, help));
  PetscCall(PetscOptionsGetInt(NULL, bag->bagprefix, nname, &odefault, &flg));
  if (flg) mdefault = odefault;

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_INT;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next          = NULL;
  item->msize         = 1;
  *(PetscInt64 *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterBoolArray - add a n `PetscBool` values to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag   - the bag of values
. addr  - location of boolean array in struct, for example `&params->b`
. msize - number of entries in array
. name  - name of the boolean array
- help  - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterBoolArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;
  PetscInt     i, tmp = msize;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) {
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
    for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%" PetscInt_FMT " ", *((PetscInt *)addr) + i));
    PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
  }
  PetscCall(PetscOptionsGetBoolArray(NULL, bag->bagprefix, nname, (PetscBool *)addr, &tmp, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_BOOL;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next  = NULL;
  item->msize = msize;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterString - add a string value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of start of string in struct, for example `&params->mystring`
. msize    - length of the string space in the struct
. mdefault - the initial value
. name     - name of the string
- help     - longer string with more information about the value

  Level: beginner

  Note:
  The struct must have the field char mystring[`msize`]; not char *mystring

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterString(PetscBag bag, void *addr, PetscInt msize, const char *mdefault, const char *name, const char *help) PeNS
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(mdefault, 4);
  PetscAssertPointer(name, 5);
  PetscAssertPointer(help, 6);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, mdefault, help));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_CHAR;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next  = NULL;
  item->msize = msize;
  if (mdefault != (char *)addr) PetscCall(PetscStrncpy((char *)addr, mdefault, msize - 1));
  PetscCall(PetscOptionsGetString(NULL, bag->bagprefix, nname, (char *)addr, msize, NULL));
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterReal - add a `PetscReal` value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of `PetscReal` in struct, for example `&params->r`
. mdefault - the initial value
. name     - name of the variable
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterReal(PetscBag bag, void *addr, PetscReal mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%g>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, (double)mdefault, help));
  PetscCall(PetscOptionsGetReal(NULL, bag->bagprefix, nname, &mdefault, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_REAL;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next         = NULL;
  item->msize        = 1;
  *(PetscReal *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterScalar - add a `PetscScalar` value to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of `PetscScalar` in struct, for example `&params->c`
. mdefault - the initial value
. name     - name of the variable
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagSetFromOptions()`,
          `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterScalar(PetscBag bag, void *addr, PetscScalar mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%g + %gi>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, (double)PetscRealPart(mdefault), (double)PetscImaginaryPart(mdefault), help));
  PetscCall(PetscOptionsGetScalar(NULL, bag->bagprefix, nname, &mdefault, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_SCALAR;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next           = NULL;
  item->msize          = 1;
  *(PetscScalar *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagRegisterBool - add a `PetscBool` to a `PetscBag`

  Logically Collective

  Input Parameters:
+ bag      - the bag of values
. addr     - location of `PetscBool` in struct, for example `&params->b`
. mdefault - the initial value, either `PETSC_FALSE` or `PETSC_TRUE`
. name     - name of the variable
- help     - longer string with more information about the value

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterInt()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagRegisterBool(PetscBag bag, void *addr, PetscBool mdefault, const char *name, const char *help)
{
  PetscBagItem item;
  char         nname[PETSC_BAG_NAME_LENGTH + 1];
  PetscBool    printhelp;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(addr, 2);
  PetscAssertPointer(name, 4);
  PetscAssertPointer(help, 5);
  nname[0] = '-';
  nname[1] = 0;
  PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
  PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
  if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, PetscBools[mdefault], help));
  PetscCall(PetscOptionsGetBool(NULL, bag->bagprefix, nname, &mdefault, NULL));

  PetscCall(PetscNew(&item));
  item->dtype  = PETSC_BOOL;
  item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
  PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
  item->next         = NULL;
  item->msize        = 1;
  *(PetscBool *)addr = mdefault;
  PetscCall(PetscBagRegister_Private(bag, item, name, help));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagDestroy - Destroys a `PetscBag`

  Collective

  Input Parameter:
. bag - the bag of values

  Level: beginner

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagDestroy(PetscBag *bag)
{
  PetscBagItem nitem;

  PetscFunctionBegin;
  if (!*bag) PetscFunctionReturn(PETSC_SUCCESS);
  PetscAssertPointer(*bag, 1);
  nitem = (*bag)->bagitems;
  while (nitem) {
    PetscBagItem item = nitem->next;

    if (nitem->list) PetscCall(PetscStrArrayDestroy(&nitem->list));
    PetscCall(PetscFree(nitem));
    nitem = item;
  }
  if ((*bag)->bagprefix) PetscCall(PetscFree((*bag)->bagprefix));
  PetscCall(PetscFree(*bag));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagSetFromOptions - Allows setting entries to a `PetscBag` using the options database

  Collective

  Input Parameter:
. bag - the bag of values

  Level: beginner

  Note:
  The options database keys for the entries are of the form `-[bagprefix]_name value`

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagSetFromOptions(PetscBag bag)
{
  PetscBagItem nitem = bag->bagitems;
  char         name[PETSC_BAG_NAME_LENGTH + 1], helpname[PETSC_BAG_NAME_LENGTH + PETSC_BAG_HELP_LENGTH + 3];
  PetscInt     n;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscCall(PetscStrncpy(helpname, bag->bagname, sizeof(helpname)));
  PetscCall(PetscStrlcat(helpname, " ", sizeof(helpname)));
  PetscCall(PetscStrlcat(helpname, bag->baghelp, sizeof(helpname)));
  PetscOptionsBegin(bag->bagcomm, bag->bagprefix, helpname, NULL);
  while (nitem) {
    name[0] = '-';
    name[1] = 0;
    PetscCall(PetscStrlcat(name, nitem->name, sizeof(name)));
    if (nitem->dtype == PETSC_CHAR) { /* special handling for fortran required? [due to space padding vs null termination] */
      char *value = ((char *)bag) + nitem->offset;
      PetscCall(PetscOptionsString(name, nitem->help, "", value, value, nitem->msize, NULL));
    } else if (nitem->dtype == PETSC_REAL) {
      PetscReal *value = (PetscReal *)(((char *)bag) + nitem->offset);
      if (nitem->msize == 1) {
        PetscCall(PetscOptionsReal(name, nitem->help, "", *value, value, NULL));
      } else {
        n = nitem->msize;
        PetscCall(PetscOptionsRealArray(name, nitem->help, "", value, &n, NULL));
      }
    } else if (nitem->dtype == PETSC_SCALAR) {
      PetscScalar *value = (PetscScalar *)(((char *)bag) + nitem->offset);
      PetscCall(PetscOptionsScalar(name, nitem->help, "", *value, value, NULL));
    } else if (nitem->dtype == PETSC_INT) {
      PetscInt *value = (PetscInt *)(((char *)bag) + nitem->offset);
      if (nitem->msize == 1) {
        PetscCall(PetscOptionsInt(name, nitem->help, "", *value, value, NULL));
      } else {
        n = nitem->msize;
        PetscCall(PetscOptionsIntArray(name, nitem->help, "", value, &n, NULL));
      }
    } else if (nitem->dtype == PETSC_ENUM) {
      PetscEnum *value = (PetscEnum *)(((char *)bag) + nitem->offset);
      PetscInt   i     = 0;
      while (nitem->list[i++]);
      PetscCall(PetscOptionsEnum(name, nitem->help, nitem->list[i - 3], (const char *const *)nitem->list, *value, value, NULL));
    } else if (nitem->dtype == PETSC_BOOL) {
      PetscBool *value = (PetscBool *)(((char *)bag) + nitem->offset);
      if (nitem->msize == 1) {
        PetscCall(PetscOptionsBool(name, nitem->help, "", *value, value, NULL));
      } else {
        n = nitem->msize;
        PetscCall(PetscOptionsBoolArray(name, nitem->help, "", value, &n, NULL));
      }
    }
    nitem = nitem->next;
  }
  PetscOptionsEnd();
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagView - Views a bag of values as either ASCII text or a binary file

  Collective

  Input Parameters:
+ bag  - the bag of values
- view - location to view the values

  Level: beginner

  Note:
  Currently PETSc bags saved in a binary file can only be read back
  in on a machine with the same binary format.

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`, `PetscBagRegisterEnum()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`
@*/
PetscErrorCode PetscBagView(PetscBag bag, PetscViewer view)
{
  PetscBool    isascii, isbinary;
  PetscBagItem nitem = bag->bagitems;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscValidHeaderSpecific(view, PETSC_VIEWER_CLASSID, 2);
  PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERASCII, &isascii));
  PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERBINARY, &isbinary));
  if (isascii) {
    if (bag->bagprefix) {
      PetscCall(PetscViewerASCIIPrintf(view, "PetscBag Object:  %s (%s) %s\n", bag->bagname, bag->bagprefix, bag->baghelp));
    } else {
      PetscCall(PetscViewerASCIIPrintf(view, "PetscBag Object:  %s %s\n", bag->bagname, bag->baghelp));
    }
    while (nitem) {
      if (nitem->dtype == PETSC_CHAR) {
        char *value             = ((char *)bag) + nitem->offset;
        char  tmp               = value[nitem->msize - 1]; /* special handling for fortran chars without null terminator */
        value[nitem->msize - 1] = 0;
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = %s; %s\n", nitem->name, value, nitem->help));
        value[nitem->msize - 1] = tmp;
      } else if (nitem->dtype == PETSC_REAL) {
        PetscReal *value = (PetscReal *)(((char *)bag) + nitem->offset);
        PetscInt   i;
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
        for (i = 0; i < nitem->msize; i++) PetscCall(PetscViewerASCIIPrintf(view, "%g ", (double)value[i]));
        PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
      } else if (nitem->dtype == PETSC_SCALAR) {
        PetscScalar value = *(PetscScalar *)(((char *)bag) + nitem->offset);
#if defined(PETSC_USE_COMPLEX)
        if ((double)PetscImaginaryPart(value)) {
          PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g + %gi; %s\n", nitem->name, (double)PetscRealPart(value), (double)PetscImaginaryPart(value), nitem->help));
        } else {
          PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g; %s\n", nitem->name, (double)PetscRealPart(value), nitem->help));
        }
#else
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g; %s\n", nitem->name, (double)value, nitem->help));
#endif
      } else if (nitem->dtype == PETSC_INT) {
        PetscInt i, *value = (PetscInt *)(((char *)bag) + nitem->offset);
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
        for (i = 0; i < nitem->msize; i++) PetscCall(PetscViewerASCIIPrintf(view, "%" PetscInt_FMT " ", value[i]));
        PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
      } else if (nitem->dtype == PETSC_BOOL) {
        PetscBool *value = (PetscBool *)(((char *)bag) + nitem->offset);
        PetscInt   i;
        /* some Fortran compilers use -1 as boolean */
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
        for (i = 0; i < nitem->msize; i++) {
          if (((int)value[i]) == -1) value[i] = PETSC_TRUE;
          /* the checks here with != PETSC_FALSE and PETSC_TRUE is a special case; here we truly demand that the value be 0 or 1 */
          PetscCheck(value[i] == PETSC_FALSE || value[i] == PETSC_TRUE, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Boolean value for %s %s is corrupt; integer value %" PetscInt_FMT, nitem->name, nitem->help, (PetscInt)value[i]);
          PetscCall(PetscViewerASCIIPrintf(view, " %s", PetscBools[value[i]]));
        }
        PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
      } else if (nitem->dtype == PETSC_ENUM) {
        PetscEnum value = *(PetscEnum *)(((char *)bag) + nitem->offset);
        PetscInt  i     = 0;
        while (nitem->list[i++]);
        PetscCall(PetscViewerASCIIPrintf(view, "  %s = %s; (%s) %s\n", nitem->name, nitem->list[value], nitem->list[i - 3], nitem->help));
      }
      nitem = nitem->next;
    }
  } else if (isbinary) {
    PetscInt          classid           = PETSC_BAG_FILE_CLASSID, dtype;
    PetscInt          deprecatedbagsize = 0;
    PetscViewerFormat format;
    PetscCall(PetscViewerBinaryWrite(view, &classid, 1, PETSC_INT));
    PetscCall(PetscViewerBinaryWrite(view, &deprecatedbagsize, 1, PETSC_INT));
    PetscCall(PetscViewerBinaryWrite(view, &bag->count, 1, PETSC_INT));
    PetscCall(PetscViewerBinaryWrite(view, bag->bagname, PETSC_BAG_NAME_LENGTH, PETSC_CHAR));
    PetscCall(PetscViewerBinaryWrite(view, bag->baghelp, PETSC_BAG_HELP_LENGTH, PETSC_CHAR));
    while (nitem) {
      PetscCall(PetscViewerBinaryWrite(view, &nitem->offset, 1, PETSC_INT));
      dtype = (PetscInt)nitem->dtype;
      PetscCall(PetscViewerBinaryWrite(view, &dtype, 1, PETSC_INT));
      PetscCall(PetscViewerBinaryWrite(view, nitem->name, PETSC_BAG_NAME_LENGTH, PETSC_CHAR));
      PetscCall(PetscViewerBinaryWrite(view, nitem->help, PETSC_BAG_HELP_LENGTH, PETSC_CHAR));
      PetscCall(PetscViewerBinaryWrite(view, &nitem->msize, 1, PETSC_INT));
      /* some Fortran compilers use -1 as boolean */
      if (dtype == PETSC_BOOL && (*(int *)(((char *)bag) + nitem->offset) == -1)) *(int *)(((char *)bag) + nitem->offset) = PETSC_TRUE;

      PetscCall(PetscViewerBinaryWrite(view, (char *)bag + nitem->offset, nitem->msize, nitem->dtype));
      if (dtype == PETSC_ENUM) PetscCall(PetscViewerBinaryWriteStringArray(view, (const char *const *)nitem->list));
      nitem = nitem->next;
    }
    PetscCall(PetscViewerGetFormat(view, &format));
    if (format == PETSC_VIEWER_BINARY_MATLAB) {
      MPI_Comm comm;
      FILE    *info;
      PetscCall(PetscObjectGetComm((PetscObject)view, &comm));
      PetscCall(PetscViewerBinaryGetInfoPointer(view, &info));
      PetscCall(PetscFPrintf(comm, info, "#--- begin code written by PetscViewerBinary for MATLAB format ---#\n"));
      PetscCall(PetscFPrintf(comm, info, "#$$ Set.%s = PetscBinaryRead(fd);\n", bag->bagname));
      PetscCall(PetscFPrintf(comm, info, "#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n"));
    }
  }
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagViewFromOptions - Processes command line options to determine if/how a `PetscBag` is to be viewed.

  Collective

  Input Parameters:
+ bag        - the object
. bobj       - optional other object that provides prefix (if `NULL` then the prefix in obj is used)
- optionname - option to activate viewing

  Level: intermediate

.seealso: `PetscBagCreate()`, `PetscBag`, `PetscViewer`
@*/
PetscErrorCode PetscBagViewFromOptions(PetscBag bag, PetscObject bobj, const char optionname[])
{
  static PetscBool  incall = PETSC_FALSE;
  PetscViewer       viewer;
  PetscViewerFormat format;
  const char       *prefix, *bprefix = NULL;
  PetscBool         flg;

  PetscFunctionBegin;
  if (incall) PetscFunctionReturn(PETSC_SUCCESS);
  incall = PETSC_TRUE;
  PetscAssertPointer(bag, 1);
  if (bobj) PetscCall(PetscObjectGetOptionsPrefix(bobj, &bprefix));
  prefix = bobj ? bprefix : bag->bagprefix;
  PetscCall(PetscOptionsCreateViewer(bag->bagcomm, NULL, prefix, optionname, &viewer, &format, &flg));
  if (flg) {
    PetscCall(PetscViewerPushFormat(viewer, format));
    PetscCall(PetscBagView(bag, viewer));
    PetscCall(PetscViewerFlush(viewer));
    PetscCall(PetscViewerPopFormat(viewer));
    PetscCall(PetscViewerDestroy(&viewer));
  }
  incall = PETSC_FALSE;
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagLoad - Loads a bag of values from a binary file

  Collective

  Input Parameters:
+ view - file to load values from
- bag  - the bag of values

  Level: beginner

  Note:
  You must have created and registered all the fields in the bag before loading into it. This only loads values.

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagView()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagLoad(PetscViewer view, PetscBag bag)
{
  PetscBool    isbinary;
  PetscInt     classid, bagcount, dtype, msize, offset, deprecatedbagsize;
  char         name[PETSC_BAG_NAME_LENGTH], help[PETSC_BAG_HELP_LENGTH], **list;
  PetscBagItem nitem;
  MPI_Comm     comm;
  PetscMPIInt  flag;

  PetscFunctionBegin;
  PetscValidHeaderSpecific(view, PETSC_VIEWER_CLASSID, 1);
  PetscAssertPointer(bag, 2);
  PetscCall(PetscObjectGetComm((PetscObject)view, &comm));
  PetscCallMPI(MPI_Comm_compare(comm, bag->bagcomm, &flag));
  PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "Different communicators in the viewer and bag");
  PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERBINARY, &isbinary));
  PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for this viewer type");

  PetscCall(PetscViewerBinaryRead(view, &classid, 1, NULL, PETSC_INT));
  PetscCheck(classid == PETSC_BAG_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not PetscBag next in binary file");
  PetscCall(PetscViewerBinaryRead(view, &deprecatedbagsize, 1, NULL, PETSC_INT));
  PetscCall(PetscViewerBinaryRead(view, &bagcount, 1, NULL, PETSC_INT));
  PetscCheck(bagcount == bag->count, comm, PETSC_ERR_ARG_INCOMP, "Bag in file has different number of entries %" PetscInt_FMT " then passed in bag %" PetscInt_FMT, bagcount, bag->count);
  PetscCall(PetscViewerBinaryRead(view, bag->bagname, PETSC_BAG_NAME_LENGTH, NULL, PETSC_CHAR));
  PetscCall(PetscViewerBinaryRead(view, bag->baghelp, PETSC_BAG_HELP_LENGTH, NULL, PETSC_CHAR));

  nitem = bag->bagitems;
  for (PetscInt i = 0; i < bagcount; i++) {
    PetscCall(PetscViewerBinaryRead(view, &offset, 1, NULL, PETSC_INT));
    /* ignore the offset in the file */
    PetscCall(PetscViewerBinaryRead(view, &dtype, 1, NULL, PETSC_INT));
    PetscCall(PetscViewerBinaryRead(view, name, PETSC_BAG_NAME_LENGTH, NULL, PETSC_CHAR));
    PetscCall(PetscViewerBinaryRead(view, help, PETSC_BAG_HELP_LENGTH, NULL, PETSC_CHAR));
    PetscCall(PetscViewerBinaryRead(view, &msize, 1, NULL, PETSC_INT));

    if (dtype == (PetscInt)PETSC_CHAR) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_CHAR));
    } else if (dtype == (PetscInt)PETSC_REAL) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_REAL));
    } else if (dtype == (PetscInt)PETSC_SCALAR) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, 1, NULL, PETSC_SCALAR));
    } else if (dtype == (PetscInt)PETSC_INT) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_INT));
    } else if (dtype == (PetscInt)PETSC_BOOL) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_BOOL));
    } else if (dtype == (PetscInt)PETSC_ENUM) {
      PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, 1, NULL, PETSC_ENUM));
      PetscCall(PetscViewerBinaryReadStringArray(view, &list));
      /* don't need to save list because it is already registered in the bag */
      PetscCall(PetscFree(list));
    }
    nitem = nitem->next;
  }
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagCreate - Create a bag of values. A `PetscBag` is a representation of a C struct that can be saved to and read from files,
  can have values set from the options database

  Collective

  Input Parameters:
+ comm    - communicator to share bag
- bagsize - size of the C structure holding the values, for example `sizeof(mystruct)`

  Output Parameter:
. bag - the bag of values

  Level: intermediate

  Notes:
  After creating the bag, for each entry in the C struct call the appropriate `PetscBagRegisterInt()` etc to define the C structs layout

  The size of the struct must be small enough to fit in a `PetscInt`; by default
  `PetscInt` is 4 bytes; this means a bag cannot be larger than 2 gigabytes in length.
  The warning about casting to a shorter length can be ignored below unless your struct is too large

.seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagCreate(MPI_Comm comm, size_t bagsize, PetscBag *bag)
{
  const size_t totalsize = bagsize + sizeof(struct _n_PetscBag) + sizeof(PetscScalar);

  PetscFunctionBegin;
  PetscAssertPointer(bag, 3);

  PetscCall(PetscInfo(NULL, "Creating Bag with total size %d\n", (int)totalsize));
  PetscCall(PetscCalloc(totalsize, bag));
  PetscCall(PetscIntCast(totalsize, &(*bag)->bagsize));
  (*bag)->bagcomm        = comm;
  (*bag)->bagprefix      = NULL;
  (*bag)->structlocation = (void *)(((char *)(*bag)) + sizeof(PetscScalar) * (sizeof(struct _n_PetscBag) / sizeof(PetscScalar)) + sizeof(PetscScalar));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagSetName - Sets the name of a bag of values

  Not Collective

  Level: intermediate

  Input Parameters:
+ bag  - the bag of values
. name - the name assigned to the bag
- help - help message for bag

.seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagSetName(PetscBag bag, const char name[], const char help[])
{
  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(name, 2);
  PetscAssertPointer(help, 3);
  PetscCall(PetscStrncpy(bag->bagname, name, PETSC_BAG_NAME_LENGTH - 1));
  PetscCall(PetscStrncpy(bag->baghelp, help, PETSC_BAG_HELP_LENGTH - 1));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagGetName - Gets the name of a bag of values

  Not Collective

  Level: intermediate

  Input Parameter:
. bag - the bag of values

  Output Parameter:
. name - the name assigned to the bag

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagGetName(PetscBag bag, const char **name)
{
  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(name, 2);
  *name = bag->bagname;
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagGetData - Gives back the user - access to memory that
  can be used for storing user-data-structure

  Not Collective

  Input Parameter:
. bag - the bag of values

  Output Parameter:
. data - pointer to memory that will have user-data-structure, this can be cast to a pointer of the type the C struct used in
         defining the bag

  Level: intermediate

.seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagGetData(PetscBag bag, PeCtx data)
{
  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(data, 2);
  *(void **)data = bag->structlocation;
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@
  PetscBagSetOptionsPrefix - Sets the prefix used for searching for all
  `PetscBag` items in the options database.

  Logically Collective

  Level: intermediate

  Input Parameters:
+ bag - the bag of values
- pre - the prefix to prepend all Bag item names with.

  Note:
  Must be called prior to registering any of the bag items.

.seealso: `PetscBag`, `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
          `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagSetOptionsPrefix(PetscBag bag, const char pre[])
{
  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  if (pre) {
    PetscAssertPointer(pre, 2);
    PetscCheck(pre[0] != '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
    PetscCall(PetscFree(bag->bagprefix));
    PetscCall(PetscStrallocpy(pre, &bag->bagprefix));
  } else PetscCall(PetscFree(bag->bagprefix));
  PetscFunctionReturn(PETSC_SUCCESS);
}

/*@C
  PetscBagGetNames - Get the names of all entries in the bag

  Not Collective

  Input Parameter:
. bag - the bag of values

  Output Parameter:
. names - pass in an array of char pointers to hold the names. The array must be as long as the number of items in the bag.

  Level: intermediate

.seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagSetName()`, `PetscBagCreate()`, `PetscBagGetData()`
          `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`, `PetscBagRegisterEnum()`
@*/
PetscErrorCode PetscBagGetNames(PetscBag bag, const char *names[])
{
  PetscBagItem nitem = bag->bagitems;

  PetscFunctionBegin;
  PetscAssertPointer(bag, 1);
  PetscAssertPointer(names, 2);
  for (PetscInt n = 0; nitem; ++n, nitem = nitem->next) names[n] = nitem->name;
  PetscFunctionReturn(PETSC_SUCCESS);
}
