/* texrefs.c */
 
/*****************************************************************************/
 
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
 
/*                                                                           */
 
/* AS                                                                        */
 
/*                                                                           */
 
/* TeX Convertes: Label/Citation Bookkeeping                                 */
 
/*                                                                           */
 
/*****************************************************************************/
 
 
 
#include <stdlib.h>
 
#include <string.h>
 
#include "strutil.h"
 
#include "texutil.h"
 
#include "texrefs.h"
 
 
 
/*--------------------------------------------------------------------------*/
 
 
 
typedef struct sRefSave
 
{
 
  struct sRefSave *pNext;
 
  char *pRefName, *pValue;
 
} tRefSave, *tpRefSave;
 
 
 
/*--------------------------------------------------------------------------*/
 
 
 
static tpRefSave pFirstRefSave, pFirstCiteSave;
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     AddList(tpRefSave *ppList, const char *pDescr, const char *pName, const char *pValue)
 
 * \brief  add/update list
 
 * \param  ppList list root
 
 * \param  pDescr type of list contents
 
 * \param  pName name of label
 
 * \param  pValue value of label
 
 * ------------------------------------------------------------------------ */
 
 
 
static void AddList(tpRefSave *ppList, const char *pDescr, const char *pName, const char *pValue)
 
{
 
  tpRefSave pRun, pPrev, pNeu;
 
  int cmp = -1;
 
  char err[200];
 
 
 
  for (pRun = *ppList, pPrev = NULL; pRun; pPrev = pRun, pRun = pRun->pNext)
 
    if ((cmp 
= strcmp(pRun
->pRefName
, pName
)) >= 0)  
      break;
 
 
 
  if (pRun && !cmp)
 
  {
 
    if (strcmp(pRun
->pValue
, pValue
))  
    {
 
      as_snprintf(err, sizeof(err), "value of %s '%s' has changed", pDescr, pName);
 
      tex_warning(err);
 
      DoRepass = True;
 
      pRun->pValue = as_strdup(pValue);
 
    }
 
  }
 
  else
 
  {
 
    pNeu 
= (tpRefSave
) malloc(sizeof(*pNeu
)); 
    pNeu->pRefName = as_strdup(pName);
 
    pNeu->pValue = as_strdup(pValue);
 
    pNeu->pNext = pRun;
 
    if (!pPrev)
 
      *ppList = pNeu;
 
    else
 
      pPrev->pNext = pNeu;
 
  }
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     GetList(tpRefSave *pList, const char *pDescr, const char *pName, char *pDest)
 
 * \brief  retrieve value of label
 
 * \param  pList list to search
 
 * \param  pDescr type of list contents
 
 * \param  pName name of label
 
 * \param  pDest result buffer
 
 * ------------------------------------------------------------------------ */
 
 
 
static void GetList(tpRefSave pList, const char *pDescr, const char *pName, char *pDest)
 
{
 
  tpRefSave pRun;
 
  char err[200];
 
 
 
  for (pRun = pList; pRun; pRun = pRun->pNext)
 
    if (!strcmp(pName
, pRun
->pRefName
))  
      break;
 
 
 
  if (!pRun)
 
  {
 
    as_snprintf(err, sizeof(err), "undefined %s '%s'", pDescr, pName);
 
    tex_warning(err); DoRepass = True;
 
  }
 
  strcpy(pDest
, !pRun 
? "???" : pRun
->pValue
);  
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     FreeList(tpRefSave *ppList)
 
 * \brief  free list of references
 
 * \param  ppList list to free
 
 * ------------------------------------------------------------------------ */
 
 
 
static void FreeList(tpRefSave *ppList)
 
{
 
  while (*ppList)
 
  {
 
    tpRefSave pOld = *ppList;
 
    *ppList = pOld->pNext;
 
 
 
  }
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     PrintList(const char *pFileName, tpRefSave pList, const char *pDescr)
 
 * \brief  save list to file
 
 * \param  pFileName file to write label list to
 
 * \param  pList list to dump
 
 * \param  pDescr type of list contents
 
 * ------------------------------------------------------------------------ */
 
 
 
void PrintList(const char *pName, tpRefSave pList, const char *pDescr)
 
{
 
  tpRefSave pRun;
 
  FILE 
*pFile 
= fopen(pName
, "a"); 
 
 
  if (!pFile)
 
 
 
  for (pRun = pList; pRun; pRun = pRun->pNext)
 
    fprintf(pFile
, "%s %s %s\n", pDescr
, pRun
->pRefName
, pRun
->pValue
);  
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     InitLabels(void)
 
 * \brief  reset list of labels
 
 * ------------------------------------------------------------------------ */
 
 
 
void InitLabels(void)
 
{
 
  pFirstRefSave = NULL;
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     AddLabel(const char *pName, const char *pValue)
 
 * \brief  add/update label
 
 * \param  pName name of label
 
 * \param  pValue value of label
 
 * ------------------------------------------------------------------------ */
 
 
 
void AddLabel(const char *pName, const char *pValue)
 
{
 
  AddList(&pFirstRefSave, "label", pName, pValue);
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     GetLabel(const char *pName, char *pDest)
 
 * \brief  retrieve value of label
 
 * \param  pName name of label
 
 * \param  pDest result buffer
 
 * ------------------------------------------------------------------------ */
 
 
 
void GetLabel(const char *pName, char *pDest)
 
{
 
  GetList(pFirstRefSave, "label", pName, pDest);
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     PrintLabels(const char *pFileName)
 
 * \brief  save label list to file
 
 * \param  pFileName file to write label list to
 
 * ------------------------------------------------------------------------ */
 
 
 
void PrintLabels(const char *pFileName)
 
{
 
  PrintList(pFileName, pFirstRefSave, "Label");
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     FreeLabels(void)
 
 * \brief  free list of labels
 
 * ------------------------------------------------------------------------ */
 
 
 
void FreeLabels(void)
 
{
 
  FreeList(&pFirstRefSave);
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     InitCites(void)
 
 * \brief  reset list of citations
 
 * ------------------------------------------------------------------------ */
 
 
 
void InitCites(void)
 
{
 
  pFirstCiteSave = NULL;
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     AddCite(const char *pName, const char *pValue)
 
 * \brief  add/update citation
 
 * \param  pName name of citation
 
 * \param  pValue value of citation
 
 * ------------------------------------------------------------------------ */
 
 
 
void AddCite(const char *pName, const char *pValue)
 
{
 
  AddList(&pFirstCiteSave, "citation", pName, pValue);
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     GetCite(char *pName, char *pDest)
 
 * \brief  retrieve value of citation
 
 * \param  pName name of citation
 
 * \param  pDest result buffer
 
 * \return
 
 * ------------------------------------------------------------------------ */
 
 
 
void GetCite(char *pName, char *pDest)
 
{
 
  GetList(pFirstCiteSave, "citation", pName, pDest);
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     PrintCites(const char *pFileName)
 
 * \brief  save list of citations to file
 
 * \param  pFileName destination file name
 
 * ------------------------------------------------------------------------ */
 
 
 
void PrintCites(const char *pFileName)
 
{
 
  PrintList(pFileName, pFirstCiteSave, "Citation");
 
}
 
 
 
/*!------------------------------------------------------------------------
 
 * \fn     FreeCites(void)
 
 * \brief  free list of citations
 
 * ------------------------------------------------------------------------ */
 
 
 
void FreeCites(void)
 
{
 
  FreeList(&pFirstCiteSave);
 
}