
/*  alias.c
 *
 *  Alias expansion and maintenance for lafe.
 */

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

static int aliases=0;
static char **key=NULL;		/* alias names */
static char **value=NULL;	/* alias definitions */
static int width=0;		/* size of largest alias key */


static void print_aliases() {
  int i;
  for (i=0;i<aliases;i++) {
    printf("%-*s %s\n",width,key[i],value[i]);
  }
  printf(" %d aliases\n",aliases);
  return;
}


/* look up name in alias database and return index.  Should do a
 * binary search.  Returns -1 if name is not found. */
static int find_alias(char *name) {
  int i;
  for (i=0;i<aliases;i++) {
    if (!strcmp(name,key[i])) return i;
  }
  return -1;
}

static void remove_alias(char *name) {
  int i;
  
  i = find_alias(name);
  if (i>=0) {
    free(key[i]);
    free(value[i]);
    aliases--;
    key[i]=key[aliases];
    value[i]=value[aliases];
  } else {
    printf("%s not defined\n",name);
  }
}

static void define_alias(char *name,char *definition) {
  int i;
  int w;

  w=strlen(name);
  if (w>width) width=w;

  i=find_alias(name);
  if (i>=0) {
    free(value[i]);
    value[i]=strdup(definition);
  } else {
    key=realloc(key,(aliases+1) * sizeof(*key));
    value=realloc(value,(aliases+1) * sizeof(*value));
    key[aliases]=strdup(name);
    value[aliases]=strdup(definition);
    aliases++;
  }
}


/* alias expansion.  Tokenizes arg and adds tokens to environment $1 $2 .... */
/* not finished */
static void tokenize(char *arg) {
  int start,end;
  char c,buffer[8];
  int i;

  putvar("*",arg);

  /* put each fragment of arg into environment variables */
  i=0;
  for (start=0;arg[start];start++) {
    if (!isspace(arg[start])) {
      for (end=start+1;arg[end] && !isspace(arg[end]);end++) ;

      c=arg[end];
      arg[end]=0;
      sprintf(buffer,"%d",++i);
      putvar(buffer,arg+start);
      arg[end]=c;
      start=end;
    }
  }

  sprintf(buffer,"%d",++i);
  clearvar(buffer);
}

  

/* line must be individually malloced.  If the alias is expanded, line will
   be freed by expand_alias, and a new line returned */
char *expand_alias(char *line) {
  int i,j,k;
  char *alias,*semi;

  for (i=0;line[i] && isspace(line[i]);i++) ;

  for (j=i;line[j] && !isspace(line[j]);j++) ;

  /* attempt to locate the alias index for this line */
  {
    char c;
    c=line[j];   line[j]=0;
    k=find_alias(line+i);
    line[j]=c;
  }

  /* no alias found, so return line */
  if (k<0) return line;

  /* expand ;'s in alias */
  alias=strdup(value[k]);
  semi=strchr(alias,';');
  while (semi) {
    *semi='\n';
    semi=strchr(semi+1,';');
  }

     
  /* advance j to next character */
  for (;line[j] && isspace(line[j]);j++) ;

  /* if there are $'s in the alias, fill variables and return alias value */
  if (strchr(alias,'$') || strchr(alias,'\n')) {
    tokenize(line+j);
    free(line);
    return alias;

    /* otherwise, replace the first word and append arguments */
  } else {
    int len;
    char *newline;

    len=strlen(alias);
    newline=malloc(len+strlen(line+j)+2);
    strcpy(newline,alias);
    newline[len]=' ';
    strcpy(newline+len+1,line+j);
    free(line);
    free(alias);
    return newline;
  }
}


/* no arguments prints the alias database.
 * one argument delete the alias for that argument.
 * two arguments defines a new alias.
 */
void alias(char *line) {
  int i,j,k;

  i=0;

  /* print alias database */
  if (!line || !*line) {
    print_aliases();
    return;
  }

  /* alias name starts at i, ends at j.  Def starts at k. */
  /* get name of new or old alias */
  for (j=i;line[j] && !isspace(line[j]);j++) ;

  /* skip whitespace */
  for (k=j;line[k] && isspace(line[k]);k++) ;

  /* delete definition of name */
  if (!line[k]) {
    line[j]=0;
    remove_alias(line+i);
    return;
  }

  line[j]=0;
  define_alias(line+i,line+k);
}

