/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2020 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: December 2020 */


/* This file contains initializing and other housekeeping functions. */


#include "rdargs.h"
#include "pmwhdr.h"
#include "outhdr.h"

/* NO_PMWRC is set when --disable-pmwrc is given to "configure". */

#ifndef NO_PMWRC
#include <pwd.h>
#include <unistd.h>
#endif



/*************************************************
*         Read a MIDI translation file           *
*************************************************/

/* These files are short: reading them twice in order to get the correct size
doesn't take much time and saves much hassle. The files contain translation
between names and MIDI voice numbers or names and MIDI "pitches" for untuned
percussion.

Arguments:
  anchor     where to build
  filename   the file name

Returns:     nothing; if the file fails to open, no action is taken
*/

void
read_midi_translation(uschar **anchor, uschar *filename)
{
FILE *f = Ufopen(filename, "r");
int length = 0;
uschar *p;
uschar line[60];

if (f == NULL) return;

while (Ufgets(line, 60, f) != NULL)
  {
  line[Ustrlen(line)-1] = 0;
  if (!isdigit(line[0])) continue;  /* Ignore line not starting with a digit */
  length += Ustrlen(line+4) + 2;
  }

if (length == 0) return;            /* No usable text in the file */

/* We store the file in one long byte string. Each name is followed by a zero
byte and then a binary byte containing its number. */

*anchor = malloc(length+1);
p = *anchor;

rewind(f);
while (Ufgets(line, 60, f) != NULL)
  {
  line[Ustrlen(line)-1] = 0;
  if (!isdigit(line[0])) continue;
  Ustrcpy(p, line+4);
  p += Ustrlen(p) + 1;
  *p++ = Uatoi(line);
  }

/* An empty name marks the end of the list */

*p = 0;
fclose(f);
}


/*************************************************
*              Local initialization              *
*************************************************/

/* This is called before argument decoding is done. It is passed the argument
list, and it has the opportunity of modifying that list as it copies it into a
new vector. Unless configured not to include this code, we search for a .pmwrc
file and stuff it on the front of the arguments.

Arguments:
  argc          argc from main()
  argv          argv from main()
  nargv         where to return the possibly modified argv
  arg_pattern   the argument decoding pattern, to check for validity

Returns:        new argc value
*/

int
init_command(int argc, char **argv, char **nargv, const char *arg_pattern)
{
int ap = 0;
int nargc = 0;

(void)argc;   /* Unused; avoid compiler warning */

nargv[nargc++] = argv[ap++];    /* Program name */

if (argv[1] != NULL && strcmp(argv[1], "-norc") == 0)
  {
  (void)arg_pattern;
  ap++;   /* Just skip over -norc if it's first; don't read the file */
  }

/* Processing ~/.pmwrc needs to be cut out on non-Unix-like systems. If -norc
is given, it doesn't matter because that's what is happening by default. */

#ifndef NO_PMWRC
else
  {
  struct passwd *pw = getpwuid(geteuid());
  if (pw != NULL)
    {
    uschar buff[256];
    struct stat statbuf;

    Ustrcpy(buff, pw->pw_dir);
    Ustrcat(buff, "/.pmwrc");

    if (stat(CS buff, &statbuf) == 0)
      {
      arg_result results[64];
      FILE *f = Ufopen(buff, "r");

      /* Failure to open a file that statted OK is a hard error */

      if (f == NULL) error_moan(ERR41, buff, strerror(errno));

      /* Add items from the file */

      while (fgets(CS buff, sizeof(buff), f) != NULL)
        {
        uschar *p = buff;
        while (isspace(*p)) p++;
        while (*p != 0)
          {
          uschar *pp = p;
          while (*p != 0 && !isspace(*p)) p++;
          nargv[nargc] = malloc(p - pp + 1);
          Ustrncpy(nargv[nargc], pp, p - pp);
          nargv[nargc++][p-pp] = 0;
          while (isspace(*p)) p++;
          }
        }
      fclose(f);

      /* Check that what we have obtained from the .pmwrc file is a complete
      set of options; we don't want to end up with one that expects a data
      value, because that would subvert the argument on the real command line,
      possibly doing damage. */

      if (rdargs(nargc, nargv, arg_pattern, results) != 0)
        error_moan(ERR124, results[0].text, results[1].text);  /* Hard */
      }

    /* stat() problem other than file not found is serious */

    else if (errno != ENOENT) error_moan(ERR41, buff, strerror(errno));  /* Hard */
    }
  }
#endif  /* NO_PMWRC */

/* Copy the remaining stuff from the original command line */

while (argv[ap] != NULL) nargv[nargc++] = argv[ap++];
nargv[nargc] = NULL;

return nargc;
}



/*************************************************
*            Relativize a file name              *
*************************************************/

/* The name must be in a buffer that is long enough to take the additional path
if necessary, because it is modified in place. If the name does not start with
'/', we make it relative to the main input file name.

Argument:
  name       the name under consideration
  len        the total buffer length

Returns:     nothing
*/

void
sys_relativize(uschar *name, int len)
{
int im, in;
DEBUG(("sys_relativize(%s) entered\n", name));
if (name[0] == '/' || main_filename == NULL) return;
im = Ustrlen(main_filename);
while (im > 0 && main_filename[--im] != '/') {}
if (im != 0) im++;
in = Ustrlen(name);
if (im + in + 1 > len)
  error_moan(ERR136, "Fully qualified file name", len);  /* Hard */
memmove(name + im, name, in + 1);
memcpy(name, main_filename, im);
DEBUG(("relativized to %s\n", name));
}

/* End of init.c */
