/*
 * Copyright (C) 2023 Yubico AB - See COPYING
 */

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#include "util.h"

static int buf_write(uint8_t **dst, size_t *size, const void *src, size_t n) {
  if (*size < n) {
    return -1;
  }

  memcpy(*dst, src, n);
  *dst += n;
  *size -= n;

  return 0;
}

static int buf_write_byte(uint8_t **dst, size_t *size, uint8_t c) {
  return buf_write(dst, size, &c, sizeof(c));
}

static const char *lookup(char var, const char *user) {
  switch (var) {
    case 'u':
      return user;
    case '%':
      return "%";
    default:
      // Capture all unknown variables (incl. null byte).
      return NULL;
  }
}

char *expand_variables(const char *str, const char *user) {
  uint8_t *tail, *head;
  size_t size = PATH_MAX;
  int ok = -1;

  if (str == NULL || (tail = head = malloc(size)) == NULL) {
    return NULL;
  }

  for (; *str != '\0'; str++) {
    if (*str == '%') {
      str++;
      const char *value = lookup(*str, user);
      if (value == NULL || *value == '\0' ||
          buf_write(&head, &size, value, strlen(value)) != 0) {
        goto fail;
      }
    } else if (buf_write_byte(&head, &size, (uint8_t)*str) != 0) {
      goto fail;
    }
  }

  ok = buf_write_byte(&head, &size, '\0');

fail:
  if (ok != 0) {
    free(tail);
    return NULL;
  }
  return (char *) tail;
}