muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* editor.c */
/* $Id: editor.c,v 1.4 1993/08/22 04:54:02 nils Exp $ */

#include <stdio.h>
#include <sys/types.h>
#ifdef NeXT
#include <sys/dir.h>
#else
# include <dirent.h>
#endif
#include "interface.h"
#include "db.h"
#include "net.h"
#include "editor.h"
#include "externs.h"


static void prompt(dsc)
     struct descriptor_data *dsc;
{
  (void)queue_string(dsc, EPROMPT);
}

static void print(dsc, message, option)
     struct descriptor_data *dsc;
     char *message;
     int option;	/* true if display for no prompts; false otherwise */
{
  (void)queue_string(dsc, message);
  (void)queue_write(dsc, "\n", 1);
}
int valid_filename P((char *));
int valid_filename(fname)
     char *fname;
{
  char *k;
  puts(fname);
  if (!fname || *fname == '\0') {
    puts("null");
    return 0;
  }
  if (!strncmp (fname, "../", 3) ||
      !strcmp (fname, "..")) {
    puts("back");
    return 0;
  }
  if ((k = strchr (fname, '/')))
    return valid_filename (k+1);
  puts("ok.");
  return 1;
}

void do_mkdir(player, raw_fname)
     dbref player;
     char *raw_fname;
{

  if(!valid_filename(raw_fname)) {
    notify(player, "Sorry, that isn't a valid filename.");
    return;
  }
  if(mkdir(make_pfile(player,raw_fname),0755)<0) {
    notify(player, tprintf("Error creating %s",raw_fname));
    return;
  }
  notify(player, tprintf("directory %s created.",raw_fname));
}

void do_ls(player, raw_fname)
     dbref player;
     char *raw_fname;
/*
{
  DIR *dirlist;
#if  defined(SYSV) || defined(SYSV_MAYBE) || defined(HPUX)
  struct dirent *ent;
#else
  struct direct *ent;
#endif
  char *fname;
  char opbuf[1024];

  if (*raw_fname == '\0')
    raw_fname=".";
  else if(!valid_filename(raw_fname)) {
    notify(player,"Sorry, that isn't a valid filename.");
    return;
  }
  dirlist = opendir(fname = make_pfile(player,raw_fname));
  if(!dirlist) {
    notify(player, "Sorry, i can't open that file.");
    return;
  }
  while (ent = readdir (dirlist))
    if(strcmp(ent->d_name, "..")) {
      struct stat statbuf;
      sprintf(opbuf,"%s/%s",fname, ent->d_name);
      lstat(opbuf,&statbuf);
      sprintf(opbuf,"%-15s%c %d",
	      ent->d_name,
	      ((statbuf.st_mode&S_IFMT)==S_IFDIR)?'/':
	      ((statbuf.st_mode&S_IFMT)==S_IFLNK)?'@':
	      ' ',
	      statbuf.st_size);
      notify(player, opbuf);
    }
  closedir (dirlist);
}
*/ {}
char *make_pfile(player, fname)
     dbref player;
     char *fname;
{
  static char op[1024];
  if(strlen(fname)>900)
    fname[900]='\0';
  sprintf(op,"files/p/%d/%s", player, fname);
  return op;
}

void do_editfile(player, fname)
     dbref player;
     char *fname;
{
  struct descriptor_data *dsc;
  char *name_buffer;
  char line_buff[80];
  FILE *fp;
  struct top *head;
  struct buffer *p;
  int count = 0;
  
  if (Typeof(player) != TYPE_PLAYER) {
    notify(player,"Excuse me, but you aren't a player.");
    return;
  }
  for (dsc=descriptor_list; dsc->state==CONNECTED && dsc->player != player;
       dsc=dsc->next);
  if (dsc == NULL) {
    notify(player,"But you don't seem to be connected!");
    return;
  }
  if (*fname == '\0') {
    notify(player, "Syntax: +edit <filename>");
    return;
  }
  if (!valid_filename(fname)) {
    notify(player, "Sorry, that isn't a valid filename.");
    return;
  }
  /* make SURE filename does not overrun buffer, or disaster! */
  if (strlen(fname)+strlen(db[player].name)+10 > 80) {
    fname[80 - strlen(db[player].name) - 10] = '\0';
  }
  name_buffer = make_pfile (player, fname);

  if ((fp = fopen(name_buffer, "r")) == NULL) 
    if ((fp = fopen(name_buffer, "w")) == NULL) {
      notify(player,"Can't open/create file!");
      return;
    }
  fprintf(stderr, tprintf("Player %d(dsc %d) opened %s for editing.\n",
			  player,	dsc,name_buffer));
  MALLOC(head, struct top, 1);
  MALLOC(head->next, struct buffer, 1);
  strcpy(head->filename, name_buffer);
  dsc->edit_buff = head;
  p = head->next;
  p->next = NULL;
  while (fgets(line_buff, 80, fp) != NULL) {
    MALLOC(p->next, struct buffer, 1);
    p = p->next;
    line_buff[strlen(line_buff)-1] = '\0';
    strcpy(p->line, line_buff);
    p->next = NULL;
    count++;
  }
  head->state = COMMAND;
  head->issaved = 1;
  
  fclose(fp);
  notify(player, "Welcome to MUSEdit V1.0");
  notify(player, "Type \"h\" for help.");
  notify(player, tprintf("Editing \"%s\", %d lines.", fname, count));
  prompt(dsc);
}

void parse_range(head, range, p1, p2, start_line)
     struct top *head;
     char *range;
     struct buffer **p1;
     struct buffer **p2;
     int *start_line;
     
{
  char *c;
  int l1, l2, t, count;
  
  if (!*range) {			/* no arguments supplied */
    *p1 = head->next->next;
    *p2 = NULL;
    if (start_line) *start_line = 1;
    return;
  }
  c = strchr(range, '-');
  if ((l1 = atoi(range)) <= 0) l1 = 1;
  if (c) {
    *c++ = '\0';
    if ((l2 = atoi(c)) <= 0) l2 = 0;
  } else l2 = l1;
  if ((l1 > l2) && l2) {
    t = l1;
    l1 = l2;
    l2 = t;
  }
  *p1 = head->next->next;
  count = 1;
  while ((count < l1) && (*p1 != NULL)) {
    count++;
    *p1 = (*p1)->next;
  }
  if (!l2) {
    *p2 = NULL;
  } else {
    for (*p2 = *p1; (count < l2) && (*p2 != NULL);
	 count++, *p2 = (*p2)->next);
  }
  if (start_line) *start_line = l1;
  return;
}

void do_ehelp(player)
     dbref player;
     
{
  spit_file(player,EDIT_HELP_FILE,NULL);
  return;
}


void do_list(player, head, string)
     dbref player;
     struct top *head;
     char *string;
     
{
  struct buffer *l, *u;
  
  parse_range(head, string, &l, &u, &(head->linenum));
  while ((l != NULL) && (u->next != l)) {
    notify(player, tprintf("[%2d]: %s", head->linenum, l->line));
    l = l->next;
    head->linenum++;
  }
}

void do_esearch(player, head, string, case_sense)
     dbref player;
     struct top *head;
     char *string;
     int case_sense;
     
{
  int matches = 0, linenum = 0;
  struct buffer *s;
  char *t, *u, *v;
  
  for (s = head->next->next; s; s = s->next) {
    linenum++;
    t = s->line;
    while(*t) {
      u = t;
      v = string;
      while (*v && ((case_sense) ? *v : to_lower(*v))
	     == ((case_sense) ? *u : to_lower(*u))) v++, u++;
      if (*v == '\0') {
	matches++;
	notify(player,
	       tprintf("[%2d]: %s",linenum,s->line));
	break;
      }
      t++;
    }
  }
  if (matches == 0) notify(player, "No matches found.");
  else notify(player, tprintf("%d matches found.",matches));
}

void do_delete(dsc, player, head, string)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
     char *string;
     
{
  struct buffer *l;
  
  if ((head->state == COMMAND) && !*string) {
    print(dsc, "Really delete everything? (y/n) ", 1);
    head->state = DELETING;
  } else {
    parse_range(head, string, &(head->current),
		&(head->bound), NULL);
    head->issaved = 0;
    for (l = head->next; l->next != head->current; l = l->next);
    if (head->bound == NULL) l->next = NULL;
    else l->next = head->bound->next;
    l = head->current->next;
    while (head->current != head->bound->next) {
      free(head->current);
      head->current = l;
      l = l->next;
    }
    notify(player, "Deleted.");
  }
}

void do_write(player, head, string)
     dbref player;
     struct top *head;
     char *string;
{
  struct buffer *p;
  FILE *fp;
  char fname[80];
  
  if (head->next->next == NULL) {
    unlink(head->filename);
  } else {
    if (*string == '\0') strcpy(fname, head->filename);
    else {
      if (strlen(string)+strlen(db[player].name)+10 > 80) {
	string[80-strlen(db[player].name)-10] = '\0';
      }
      sprintf(fname, tprintf("./files/p/%s/%s",
			     db[player].name, string));
    }
    if ((fp = fopen(fname, "w")) == NULL ) {
      notify(player, "Error opening file!");
      fprintf(stderr,"File I/O error from %s.",
	      db[player].name);
      return;
    }
    for (p = head->next->next; p != NULL; p = p->next) {
      fputs(p->line, fp);
      fputs("\n", fp);
    }
    fclose(fp);
  }
  notify(player, "Written.");
  head->issaved=1;
}

void set_change(dsc, player, head, string)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
     char *string;
     
{
  head->state=CHANGE;
  parse_range(head, string, &(head->current), &(head->bound),
	      &(head->linenum));
  head->bound = head->bound->next;
  notify(player, tprintf("[%2d]: %s", head->linenum,
			 head->current->line));
  print(dsc, tprintf("[%2d]: ", head->linenum), 0);
}

void set_insert(dsc, player, head, string)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
     char *string;
{
  head->state=INSERT;
  parse_range(head, string, &(head->current), &(head->bound),
	      &(head->linenum));
  head->bound = head->current->next;
  if (head->bound == NULL) {
    notify(player, "Use \"a\" to add to the end of a file.");
    head->state=COMMAND;
    return;
  }
  notify(player, tprintf("[%2d]: %s", head->linenum,
			 head->current->line));
  print(dsc, tprintf("[%2d]: ", ++head->linenum), 0);
}

void set_add(dsc, player, head)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
{
  head->state=ADD;
  head->current = head->next;
  head->linenum = 1;
  while (head->current->next != NULL) {
    head->current = head->current->next;
    head->linenum++;
  }
  print(dsc, tprintf("[%2d]: ", head->linenum), 0);
}


void do_change(dsc, player, head, string)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
     char *string;
     
{
  if (strcmp(string,".")) {
    if (strlen(string) > 80) string[80] = '\0';
    strcpy(head->current->line, string);
    head->current = head->current->next;
    head->linenum++;
    head->issaved=0;
    if (head->current == head->bound) head->state = COMMAND;
    else {
      notify(player, tprintf("[%2d]: %s",
			     head->linenum, head->current->line));
      print(dsc, tprintf("[%2d]: ", head->linenum), 0);
    }
  } else head->state = COMMAND;
}

void do_add(dsc, head, string)
     struct descriptor_data *dsc;
     struct top *head;
     char *string;
     
{
  if (strcmp(string,".")) {
    MALLOC(head->current->next, struct buffer, 1);
    head->current = head->current->next;
    if (strlen(string) > 80) string[80] = '\0';
    strcpy(head->current->line, string);
    head->linenum++;
    print(dsc, tprintf("[%2d]: ", head->linenum), 0);
  } else {
    head->issaved=0;
    head->state = COMMAND;
    head->current->next = NULL;
  }
}

void do_insert(dsc, head, string)
     struct descriptor_data *dsc;
     struct top *head;
     char *string;
{
  if (strcmp(string,".")) {
    MALLOC(head->current->next, struct buffer, 1);
    head->current = head->current->next;
    if (strlen(string) > 80) string[80] = '\0';
    strcpy(head->current->line, string);
    head->linenum++;
    if((head->linenum%10)==0)
      print(dsc, tprintf("%2d: ", head->linenum), 0);
    head->issaved=0;
  } else {
    head->state = COMMAND;
    head->current->next = head->bound;
  }
}

void do_quit(dsc, player, head)
     struct descriptor_data *dsc;
     dbref player;
     struct top *head;
{
  if (head->state == COMMAND && !head->issaved) {
    print(dsc, "But you haven't saved your changes! Really quit? (y/n) ", 1);
    head->state = QUITTING;
  } else {
    dsc->edit_buff = NULL;
    if (head->next->next == NULL) unlink(head->filename);
    notify(player, "Bye.");
    head->state = QUITTING;
  }
}

void edit_command(dsc, player, string)
     struct descriptor_data *dsc;
     dbref player;
     char *string;
     
{
  char cmd = *string;
  struct top *head;
  
  head = dsc->edit_buff;
  if (head->state == COMMAND) {
    for (string++; *string && *string == ' '; string++);
    switch(cmd) {
    case 'c' :
    case 'C' : set_change(dsc, player, head, string);
      break;
    case 'l' :
    case 'L' : do_list(player, head, string);
      break;
    case 's' :
      do_esearch(player, head, string, 0);
      break;
    case 'S' : do_esearch(player, head, string, 1);
      break;
    case 'i' :
    case 'I' : set_insert(dsc, player, head, string);
      break;
    case 'h' :
    case 'H' : do_ehelp(player);
      break;
    case 'a' :
    case 'A' : set_add(dsc, player, head);
      break;
    case 'd' :
    case 'D' : do_delete(dsc, player, head, string);
      break;
    case 'w' :
    case 'W' : do_write(player, head, string);
      break;
    case 'q' :
    case 'Q' : do_quit(dsc, player, head);
      break;
      default  : notify(player,
			"Unknown command. (Type \"h\" for help.)");
      break;
    }
    if (head->state == COMMAND) prompt(dsc);
    return;
  } else {
    switch (head->state) {
    case CHANGE   :
      do_change(dsc, player, head, string);
      break;
    case ADD      :
      do_add(dsc, head, string);
      break;
    case INSERT   :
      do_insert(dsc, head, string);
      break;
    case DELETING :
      if (to_lower(*string) == 'y')
	do_delete(dsc, player, head, "");
      head->state = COMMAND;
      break;
    case QUITTING :
      if (to_lower(*string) == 'y') {
	do_quit(dsc, player, head);
	return;
      } else head->state = COMMAND;
    }
    if (head->state == COMMAND) prompt(dsc);
  }
}

/********************************* EDITOR.C *********************************/