/*  var.c
 *
 *  Variable expansion and maintenance.
 *
 *  All variables are stored as enviroment variables.
 */

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "lafe.h"

extern char **environ;

static void printvar() {
  int i;
  for (i=0;environ[i];i++) {
    printf("%s\n",environ[i]);
  }
}

char *getvar(char *name) {
  char *v;
  v = getenv(name);
  if (v) return strdup(v);
  else return NULL;
}

void putvar(char *name,char *val) {
  setenv(name,val,1);
}

void clearvar(char *name) {
  unsetenv(name);
}



/* variable expansion, return a malloced line */
char *expand_variables(char *line) {
  char *oldline;
  int size;
  int src,dst,i;
  char *var,*val;

  /* exit fast if no $ in line */
  /* if (!strchr(line,'$')) return line; */
  
  oldline=line;
  size=256;
  line=malloc(size);
  if (!line) {
    perror("malloc");
    return oldline;
  }

  for (src=dst=0;oldline[src];) {
    /* begining of a variable */
    if (oldline[src] == '$') {

      /* allocate var to be the variable name */

      /* a general {} variable */
      if (oldline[++src]=='{') {
	for (i=(++src);oldline[i] && oldline[i]!='}';i++) ;
	var=malloc(i-src+1);
	strncpy(var,oldline+src,i-src);
	var[i-src]=0;
	src=i+1;

	/* a simple alphanumeric variable */
      } else if (isalnum(oldline[src])) {
	for (i=src;isalnum(oldline[i]);i++) ;
	var=malloc(i-src+1);
	strncpy(var,oldline+src,i-src);
	var[i-src]=0;
	src=i;

	/* single character variable */
      } else {
	var=malloc(2);
	var[0]=oldline[src];
	var[1]=0;
	src++;
      }
      
      /* get value and copy into line at point dst */
      val=getvar(var);
      if (!val) {
	if (verbose) fprintf(stderr,"%s not defined\n",var);
      } else {
	for (;*val;val++) {
	  line[dst++] = *val;
	  if (dst>=size-1) {
	    line=realloc(line,size*=2);
	  }
	}
      }
      free(var);


      /* everything between '' is returned verbatim, without the quotes.
       * needed to define aliases with runtime variables */
    } else if (oldline[src]=='\'') {
      for (src++;oldline[src] && oldline[src]!='\'';src++) {
	line[dst++]=oldline[src];
	if (dst>=size-1) {
	  line=realloc(line,size*=2);
	}
      }
      if (oldline[src]) src++;


      /* copy character from src to dst */
    } else {
      line[dst++]=oldline[src++];
      if (dst>=size-1) {
	line=realloc(line,size*=2);
      }
    }
  }

  /* terminate string */
  line[dst]=0;

  free(oldline);

  return line;
}




/* local commands to affect variables */
  
void setvar(char *line) {
  int i,j;

  for (i=0;line[i] && !isspace(line[i]);i++) ;
  if (!line[i]) { printvar();    return;  }

  for (j=i;line[j] && isspace(line[j]);j++) ;
  line[i]=0;
  if (line[j]) putvar(line,line+j); else clearvar(line);
}


