/*
 * Port. This file contains everything you ever wanted to do with a 
 * string.
 *
 * Copyright 1992 by the Massachusetts Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 *
 * Tom Coppeto
 * MIT Network Operations
 * 26 January 1992
 *
 *    $Source: /afs/.net/tools/src/port/RCS/string_utils.c,v $
 *    $Author: tom $
 *    $Locker: tom $
 *    $Log: string_utils.c,v $
 * Revision 1.4  1993/10/18  15:22:54  tom
 * *** empty log message ***
 *
 * Revision 1.3  92/02/27  18:52:33  tom
 * *** empty log message ***
 * 
 * Revision 1.2  92/02/03  10:02:40  tom
 * rt compiler error fixed with signal cast
 * 
 * Revision 1.1  92/02/02  13:02:36  tom
 * Initial revision
 * 
 */

#ifndef lint
static char *rcsid = "$Header: /afs/.net/tools/src/port/RCS/string_utils.c,v 1.4 1993/10/18 15:22:54 tom Exp tom $";
#endif

#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <ctype.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <mit-copyright.h>
#include "port.h"

#ifdef sgi
#include <sys/ttold.h>
#endif /* sgi */

#ifdef GNU_LEDIT
extern int (*rl_startup_hook)();
extern char *rl_line_buffer;
extern int rl_point;
extern int rl_end;
extern int errno;
#endif

static int init_edit_line();
static char *edit_line;
char *copy_string();
static char lbuf[BUFSIZ];
extern int errno;
struct sgttyb ttyb;

char *buf = (char *) NULL;
static int bufsize = 0;


int
input_number(prompt, x)
     char *prompt;
     int  x;
{
  char num[10];
  char def[10];
  int n;

  bzero(def, sizeof(def));
  if(x >= 0)
    sprintf(def, "%d", x);

  for(;;)
    {
      get_prompted_input(prompt, def, num, sizeof(num)-1);
      if(string_equiv(num, "?", 1))
      {
        printf("you are expected to enter a number.\n");
        continue;
      }

      if(!isnumber(num))
      continue;
      n = atoi(num);
      return(n);
    }
}


char *
input_string(prompt, x)
     char *prompt;
     char *x;
{
  char buf[BUFSIZ];

  bzero(buf, sizeof(buf));
  for(;;)
    {
      if(get_prompted_input(prompt, x, buf, sizeof(buf)))
	return((char *) NULL);
      if(*buf == '\0')
	return((char *) NULL);
      if(is_blank(buf))
	return((char *) NULL);
      if(*buf != '?')
	break;
      printf("You are expected to enter some text here.\n");
    }
  if(x)
    free(x);
  return(copy_string(buf));
}


/*
 * Function:    numeric_suffix() 
 * Decsription: decides what suffix best succeeds given number
 * Returns:     suffix
 */


char *
numeric_suffix(n)
     int n;
{
  while(n/10 > 0)
    n /= 10;

  switch(n)
    {
    case 1: 
      return("st");
    case 2:
      return("nd");
    case 3:
      return("rd");
    default:
      return("th");
    }
}



/*
 * Function:    article() 
 * Decsription: decides if "a" or "an" will best precede given word
 * Returns:     "a" or "an"
 */


char *
article(word)
     char *word;
{
  switch(*word)
    {
    case 'a':
    case 'e':
    case 'i':
    case 'o':
    case 'u':
      return("an");
    }

  switch(*word)
    {
    case 'l':
    case 'f':
    case 'm':
    case 'n':
    case 'r':
    case 's':
      switch(*(word+1))
        {
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':
          return("a");
        default:
          return("an");
        }
    default:
      return("a");
    }
}



/*
 * Function:    uncase() 
 * Decsription: converts a string to lower case letters. It also
 *              strips leading whitespace from the string.
 * Returns:     Nothing.
 */

void 
uncase(string)
    char *string;
{
  char *s1 = string;
  
  while (isspace (*string))
    string++;
  while (*string) 
    {
      *s1++ = isupper (*string) ? tolower (*string) : *string;
      string++;
    }
  *s1 = '\0';
}



/*
 * Function:    case() 
 * Decsription: converts a string to upper case letters. It also
 *              strips leading whitespace from the string.
 * Returns:     Nothing.
 */

void 
upcase(string)
    char *string;
{
  char *s1 = string;
  
  while (isspace (*string))
    string++;
  while (*string) 
    {
      *s1++ = islower (*string) ? toupper (*string) : *string;
      string++;
    }
  *s1 = '\0';
}


/*
 * Function:    cap() 
 * Decsription: capitalizes first letter of the string.
 * Returns:     the string
 * Notes:
 */

char *
cap(string)
     char *string;
{
  static char buf[BUFSIZ];
  char c;

  strncpy(buf, string, BUFSIZ);
  c = buf[0];
  if(!isupper (c))
    buf[0] = toupper (c);
  return(buf);
}


char *
reverse(string)
     char *string;
{
  static char buf[BUFSIZ];
  char *c;
  char *d;

  d = buf;
  c = &string[strlen(string)-1];
  while(c != string)
    *d++ = *c--;
  *d++ = *c;
  *d = '\0';
  return(buf);
}


char *
strip_trailing_white_space(string)
     char *string;
{
  char *c;

  c = (char *) index(string, '\0');
  while(c && (c != string))
    {
      --c;
      if((*c == ' ') || (*c == '\t'))
	*c = '\0';
      else
	break;
    }
  return(string);
}


/*
 * Function:    isnumber() 
 * Decsription: checks to see if given string is a number
 * Returns:     SUCCESS/ERROR
 */

int 
isnumber(string)
     char *string;
{
  if (!string)
    return(0);
  while (*string) 
    {
      if(!isdigit(*string))
	return(0);
      ++string;
    }
  return(1);
}





char *
itoa(num)
     int num;
{
  static char buf[32];

  sprintf(buf, "%d", num);
  return(buf);
}



char *
format_number(num, ret)
     int num;
     char *ret;
{
  char buf[BUFSIZ];
  static char string[BUFSIZ];
  int  i = 0;
  int  j = 0;
  int  len;
  int  pos = 0;

  (void) sprintf(buf, "%d", num);
  len = strlen(buf);
  len = len % 3;

  if(len == 2)
    pos = 1;
  if(len == 1)
    pos = 2;
  if(len == 0)
    pos = 0;

  while(buf[i] != '\0')
    {
      string[j] = buf[i];
      if((pos == 2) && (buf[i+1] != '\0'))
        {
          ++j;
          string[j] = ',';
          pos = -1;
        }
      ++j;
      ++i;
      ++pos;
    }
  string[j] = '\0';
  if(ret != (char *) NULL)
    (void) strcpy(ret, string);
  return(string);
}



char *
format_uptime(t)
     int t;
{
  char *c;
  int j;

  bzero(lbuf, sizeof(lbuf));
  c = lbuf;
  j = t/86400;
  if(j > 0)
    sprintf(c, "%d day%s ", j, j > 1 ? "s" : "");
  c += strlen(c);
  t = t % 86400;
  j = t/3600;
  if(j > 0)
    sprintf(c, "%d hr%s ", j, j > 1 ? "s" : "");
  c += strlen(c);
  t = t % 3600;
  j = t / 60;
  if(j > 0)
    sprintf(c, "%d min ", j);
  c += strlen(c);
  t = t % 60;
  sprintf(c, "%d sec", t);
  return(lbuf);
}


  
void
strip_commas(str)
     char *str;
{
  char *c;
  char *s;

  bzero(lbuf, sizeof(lbuf));
  c = lbuf;
  s = str;
  while(s && *s)
    {
      if(*s != ',')
	*c++ = *s;
      ++s;
    }
  *c++ = '\0';
  strcpy(str, lbuf);
}



/*
 * Function:    get_prompted_input() prompts the user for a command string.
 * Arguments:   prompt:         Prompt to use.
 *              buf:            Buffer to hold command line.
 *              len:            max length of buffer
 * Returns:     Nothing.
 * Notes:
 *      First, we print the prompt, then read a string using fgets().
 *      If a ^D is typed, we exit.
 */

int
get_prompted_input(prompt, def, buf, len)
     char *prompt;              /* Prompt to use. */
     char *def;
     char *buf;                 /* Input line buffer. */
     int  len;
{
  char pbuf[BUFSIZ];
  char *cp;

#ifdef GNU_LEDIT
  if(def && (strlen(def) > 40))
    sprintf(pbuf, "%s [%40.40s...] ", prompt, def ? def : "");
  else
    sprintf(pbuf, "%s [%s] ", prompt, def ? def : "");

#else

  printf("%s ", prompt);
  if(def)
    {
      if(strlen(def) > 40)
	printf("[%40.40s...] ", def);
      else
	printf("[%s] ", def);
    }

#endif

#ifdef GNU_LEDIT

  if(((cp = (char *) readline(pbuf)) == (char *) EOF) || (*cp =='\0'))
    {
      if(def)
	strncpy(buf, def, len - 1);
      return(0);
    }

  
  if((*cp == '~') && (*(cp+1) == 'e'))
    {
      edit_line = def;
      rl_startup_hook = init_edit_line;
      if((cp = (char *) readline("-> ")) == (char *) EOF)
	return-1);
      rl_startup_hook = 0;
    }
  strncpy(buf, cp, len-1);
  strip_trailing_white_space(buf);
  return(0);

#else

  if (fgets(buf, len, stdin) == (char *) NULL)
    {
      printf("\n");
      return(-1);
    }
  buf[strlen(buf)-1] = '\0';
  if((*buf == '\0') && def)
    strncpy(buf, def, len - 1);
  return(0);

#endif
}


static int
init_edit_line()
{
  if(edit_line)
    {
     
      /*strcpy(rl_line_buffer, edit_line);*/
#ifdef GNU_LEDIT
      rl_insert_text(edit_line);
      rl_end   = strlen(edit_line);
      rl_point = rl_end;
#endif
    }
  return;
}



is_blank(s)
     char *s;
{
  if(s == (char *) NULL)
    return(0);

  while(s && *s)
    if((*s != '\n') && (*s != ' ') && (*s != '\t')) 
      return(0);
    else
      ++s;

  return(1);
}



char *
strip_trailing_newlines(s)
     char *s;
{
  char *c;
  
  c = s;
  if(*c == '\n')
    *c = ' ';

  while((c = (char *) index(c, '\n')) != (char *) NULL)
    {
      ++c;
      if(is_blank(c))
	*(c-1) = ' ';
    }
  return(s);
}



char *
get_prompted_text(def, edit)
     char *def;
     int edit;
{
  char *editor_path   = (char *) NULL;
  char *editor_path_e = (char *) NULL;
  char *editor_path_v = (char *) NULL;
  int pid;
  void (*handler)();
  union wait wbuf;
  struct stat buf;
  char buffer[BUFSIZ];
  char temp[64];
  FILE *the_file = NULL;
  int fd;
  int cc;
  int ccc;
  char *c = (char *) NULL;
  char *fn;

  sprintf(temp, "/tmp/iapXXXXXX");
  fn = (char *) mktemp(temp);
  sprintf(temp, "%s", fn);
  editor_path_e = (char *) getenv("EDITOR");
  if (!editor_path_e) 
    editor_path_e = "/bin/ed";
  editor_path_v = (char *) getenv("VISUAL");
  if (!editor_path_v) 
    editor_path_v = "/usr/ucb/vi";

  the_file = fopen(temp, "w");
  if (!the_file) 
    {
      perror(temp);
      printf("Error opening file: %d\n", errno);
      return((char *) NULL);
    }
	
  ftruncate(fileno(the_file), 0);
  fchmod(fileno(the_file), 0700);
  if(def)
    fprintf(the_file, "%s", def);
  if(!edit)
    {
      printf("(end with ^D or '.' on a line by itself)\n");
      for (;;) 
	{
	  if ((fgets(buffer, sizeof(buffer), stdin) == NULL) || 
	      !strcmp(buffer, ".\n")) 
	    break;
	  else 
	    if (!strcmp(buffer, "\\f\n")) 
	      {
		editor_path = editor_path_e;
		break;
	      } 
	    else 
	      if (!strcmp(buffer, "~e\n")) 
		{
		  editor_path = editor_path_e;
		  break;
		} 
	      else 
		if (!strcmp(buffer, "~v\n")) 
		  {
		    editor_path = editor_path_v;
		    break;
		  } 
		else 
		  {
		    fputs(buffer, the_file);
		  }
	}
    }
  else
    editor_path = editor_path_v;

  if(editor_path) 
    {
      if (the_file) 
	{
	  clearerr(stdin);
	  fclose(the_file);
	}
      switch ((pid = fork())) 
	{
	case -1:
	  perror("couldn't fork");
	  printf("Couldn't fork, error %d\n", errno);
	  return((char *) NULL);
	case 0:
	  (void) execlp(editor_path, editor_path, temp, 0);
	  (void) perror(editor_path);
	  exit(1);
	default:
	  break;
	}
      handler = (void *) signal(SIGINT, SIG_IGN);
      while (wait(&wbuf) != pid)
	;
      (void) signal(SIGINT, handler);
      if (WIFSIGNALED(wbuf))
	return((char *) NULL);
      if (wbuf.w_retcode != 0)
	return((char *) NULL);
    } 
  else 
    {
      clearerr(stdin);
      fclose(the_file);
    }

  if ((stat (temp, &buf) != 0) || (buf.st_size == 0))
    {
      unlink(temp);
    }
  else
    {
      fd = open(temp, O_RDONLY, 0);
      if (fd < 0) 
	{
	  perror(temp);
	  printf("Error opening file: %d\n",errno);
	  return((char *) NULL);
	}
      if((c = (char *) malloc(sizeof(char *) * (buf.st_size + 1))) == 
	 (char *) NULL)
	{
	  perror("");	  
	  return((char *) NULL);
	}
      ccc = 0;
      while ((cc = read(fd, c+ccc, buf.st_size)) > 0)
	ccc += cc;
      c[ccc-1] = '\0';
      (void) close(fd);
      (void) unlink(temp);
    }
  return(c);
}


void
raw_mode()
{
#ifdef POSIX
  cbreak();
#else /* POSIX */
  ioctl(0, TIOCGETP, &ttyb);
  ttyb.sg_flags = ttyb.sg_flags & ~ECHO | CBREAK /* | RAW */;
  ioctl(0, TIOCSETP, &ttyb);
#endif /* POSIX */
}



void
cooked_mode()
{
#ifdef POSIX
  nocbreak();
#else /* POSIX */
  ioctl(0, TIOCGETP, &ttyb);
  ttyb.sg_flags = ttyb.sg_flags & /* ~RAW | */  ~CBREAK | ECHO;
  ioctl(0, TIOCSETP, &ttyb);
#endif /* POSIX */
}



int
get_prefixed_input(prompt, inbuf, len)
     char *prompt;
     char *inbuf;
     int len;
{
  char *p;
  char c;

  p = inbuf;
  if(prompt != (char *) NULL)
    write(1, prompt, sizeof(char) * strlen(prompt));

  if (inbuf != (char *) NULL)
    {
      write(1, inbuf, sizeof(char *) * strlen(inbuf));
      p += strlen(inbuf);
    }

  raw_mode();
  while (1)
    {
      c = getchar();		/* Get an input key... */

      if (c == '\n')		/* RETURN key, end input */
	break;
      if (iscntrl(c))
	{
	  if (c == ttyb.sg_erase) /* DELETE key */
	    if (p > inbuf)	/* if not at beggining of inbuf, back */
	      {			/* up pointer, wipe out char, and delete */
		p--;		/* the character on the screen. */
		*p = '\0';
		write(1, "\b \b", 3);
	      }
	  continue;
	}
      if (p < &inbuf[len - 1])	/* Just print out all other characters. */
	{
	  write(1, &c, sizeof(c));
	  *p++ = c;
	  continue;
	}
      else
	write(1, "\007", sizeof(char));
    }
  *p = '\0';
  write(1, "\n", sizeof(char));
  cooked_mode();
  return(0);
}




char *
prompt_string(prompt, prefix)
     char *prompt;
     char *prefix;
{
  char *str = (char *) NULL;
  
  bzero(lbuf, sizeof(lbuf));
  if(prefix)
    strcpy(lbuf, prefix);
  if((get_prefixed_input(prompt, lbuf, sizeof(lbuf)) == 0) &&
     (*lbuf != ('\0')))
    str = (char *) copy_string(lbuf);
  return(str);
}



char *
copy_string(string)
     char *string;
{
  char *s = (char *) NULL;

  if((s = (char *) malloc(sizeof(char) * (strlen(string)+1))) == (char *) NULL)
    fprintf(stderr, "copy_string: no memory\n");
  else
    strcpy(s, string);
  return(s);
}




char *
get_last_name(str)
     char *str;
{
  char *c;

  if(!str)
    return(str);

  c = (char *) rindex(str, ' ');
  if(!c)
    return(str);

  ++c;
  if((strncasecmp(c, "Jr", 2) == 0) || (strncasecmp(c, "Phd", 3) == 0))
    {
      c -= 2;
      while((c != str) && (*c != ' '))
	--c;

      if(c == str)
	return(str);
      
      ++c;
    }

  return(c);
}


char *
lower_case(str)
     char *str;
{
  static char buf[BUFSIZ];
  char *c;

  c = buf;
  while(str && *str)
    {
      if(islower(*str))
	*c++ = *str;
      else
	*c++ = tolower(*str);
      ++str;
      if(c - buf > sizeof(buf))
	break;
    }
  *c = '\0';
  return(buf);
}


display_file(file)
     char *file;
{
  FILE *fp;

  fp = fopen(file, "r");
  if(fp)
    {
      while(fgets(lbuf, sizeof(lbuf), fp))
	printf("%s", lbuf);
      fclose(fp);
    }
  return;
}




int
make_buf(size)
     int size;
{
  char *ptr;

  if(size < bufsize)
    return(0);
  if(buf == (char *) NULL)
    {
      if((ptr = (char *) malloc((size + 1) * sizeof(char))) == (char *) NULL)
	return(-1);
    }
  else
    if((ptr = (char *) realloc(buf, (size + 1) * sizeof(char))) == (char *) NULL)
      return(-1);
  bufsize = size + 1;
  buf = ptr;
  return(0);
}



char *
make_phys_address(v)
     objval *v;
{
  char cbuf[BUFSIZ];
  char c[16];
  int j;

  bzero(cbuf, sizeof(cbuf));
  if(v)
    for(j = 0; j < v->value.str.len; j++)
      {
	sprintf(c, "%2x ", v->value.str.str[j] & 0xff);
	strncat(cbuf, c, sizeof(cbuf) - 1);
      }
  return(cbuf);
}



strip_word(s, w)
     char *s;
     char *w;
{
  int l = strlen(w);

  while(*s)
    {
      if(strncasecmp(s, w, l) == 0) 
	strcpy(s, s+strlen(w));
      ++s;
    }
}


char *
elapsed_time(t)
     unsigned int t;
{
  static char tbuf[BUFSIZ];
  int days = 0;
  int hrs  = 0;
  int min  = 0;
  int sec  = 0;
  int j;
  
  j = t/86400;
  days = j;

  t = t%86400;
  j = t/3600;
  hrs = j;

  t = t%3600;
  j = t/60;
  min = j;

  t = t%60;
  sec = t;

  j = 0;

  if(days > 0)
    {
      sprintf(tbuf, "%d day%s ", days, days == 1 ? "" : "s");
      j = strlen(tbuf);
    }

  sprintf(tbuf+j, "%2.2d:%2.2d:%2.2d", hrs, min, sec);
  return(tbuf);
}
  
