Logo Search packages:      
Sourcecode: heaplayers version File versions

files.c

/* $Log: files.c,v $
/* Revision 1.1  2003/10/15 15:59:01  emery
/* Initial check-in.
/*
/* Revision 1.2  2003/05/08 21:42:30  emery
/* Ritual check-in.
/*
/* Revision 1.1  2001/08/23 17:20:45  emery
/* The big fig newton.
/*
/* Revision 1.1.1.1  2001/06/28 19:48:21  dgay
/* Initial import of RC tests
/*
 * Revision 1.39  1997/08/04 22:18:05  arda
 * Use oports for mudlle I/O
 * Add a bunch of primitives
 * Fix mudlle so that it compiles with g++
 *
 * Revision 1.38  1996/10/15 22:09:03  arda
 * Commit before moving stuff.
 *
 * Revision 1.37  1996/08/04 17:22:53  arda
 * New zones: allow more than 100 rooms
 * Clean up exit stuff. No macro, no bool_enter.
 * db.world.c split into handler.wld.c and model_wld.c
 *
 * Revision 1.36  1996/07/04 00:31:48  arda
 * Simple stuff, mostly.
 *
 * Revision 1.35  1996/05/14 22:13:38  arda
 * char.c:  mudlled affects
 * others: misc junk.
 *
 * Revision 1.34  1996/02/09 14:59:30  arda
 * Security holes
 *
 * Revision 1.33  1996/02/04 04:36:49  arda
 * Added fileedit, fileview.
 * Modified model_react_list for select_global.
 * Other new loader stuff ?
 *
 * Revision 1.32  1995/07/30 14:23:37  arda
 * Undocumented changes, as usual
 *
 * Revision 1.31  1995/07/15  15:24:57  arda
 * Context cleanup.
 * Remove GCDEBUG.
 *
 * Revision 1.30  1995/06/04  14:24:33  arda
 * Rename/move some files, misc. junk
 *
 * Revision 1.29  1994/10/09  06:44:06  arda
 * Libraries
 * Type inference
 * Many minor improvements
 *
 * Revision 1.28  1994/09/16  13:07:24  arda
 * Rename protect to catch.
 * New protect/unprotect functions (like dynpro/undynpro).
 *
 * Revision 1.27  1994/09/16  09:12:12  arda
 * start_process
 *
 * Revision 1.26  1994/09/01  13:05:03  arda
 * David
 *
 * Revision 1.25  1994/08/31  13:03:36  arda
 * Bug fixes (argh, no, new version of characters structures! (MD))
 *
 * Revision 1.24  1994/08/29  15:44:52  arda
 * Mudlle stuff
 *
 * Revision 1.23  1994/08/23  09:30:49  arda
 * Final(?) changes for mudlle compiler.
 * Changed code organisation in mudlle directory.
 *
 * Revision 1.22  1994/08/22  11:18:54  arda
 * Changes for mudlle compiler in MUME.
 *
 * Revision 1.21  1994/08/17  10:49:38  arda
 * Misc. fixes
 *
 * Revision 1.20  1994/08/17  10:19:54  arda
 * Improved make depend.
 * basic_load for compiler, select_reactor.
 *
 * Revision 1.19  1994/08/16  19:17:03  arda
 * Added flags to primitives for better calling sequences.
 *
 * Revision 1.15  1994/02/11  10:00:22  dgay
 * Owl: -Wall
 *      new shared string handling
 *      configuration file
 *
 * Revision 1.14  1994/02/03  19:22:33  arda
 * nothing special(3)
 *
 * Revision 1.13  1994/01/29  19:50:57  dgay
 * Owl: add file & line information to functions.
 *
 * Revision 1.12  1994/01/27  17:08:46  arda
 * Hmm.
 *
 * Revision 1.11  1994/01/07  08:09:10  dgay
 * Owl: Global events.
 *
 * Revision 1.10  1993/12/31  09:19:17  arda
 * Owl: New primitives, events to allow replacement of special procs.
 *
 * Revision 1.9  1993/12/29  10:50:38  arda
 * divers
 *
 * Revision 1.8  1993/12/04  22:41:17  arda
 * Owl: Changed room instance data to use a gdbm database.
 *      Removed number field on world.
 *      Added mudlle data on rooms.
 *      Included source for converters from update.
 *
 * Revision 1.7  1993/08/14  16:43:48  un_mec
 * Owl: New input system (with an input stack) => small interaction changes
 *
 * Revision 1.6  1993/07/25  10:59:01  un_mec
 * Owl: Move mudlle files, delete 0-length files, cancel timed ops.
 *
 * Revision 1.5  1993/06/25  15:38:08  un_autre
 * *** empty log message ***
 *
 * Revision 1.4  1993/05/29  13:25:31  un_autre
 * Bug fixes.
 *
 * Revision 1.3  1993/04/24  15:20:55  un_mec
 * Owl: Code cleanup.
 *
 * Revision 1.2  1993/04/22  18:59:16  un_autre
 * (MD) & Owl. Bug fixes. /player fixes. EVER_WHINER flag. saving_spells adjusted.
 *
 * Revision 1.1  1993/04/17  11:12:23  un_mec
 * Owl: A few new functions.
 *
 */

static char rcsid[] = "$Id: files.c,v 1.1 2003/10/15 15:59:01 emery Exp $";

#ifndef _WIN32
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#endif

#include <fcntl.h>
#include <errno.h>

#include "runtime/runtime.h"
#include "print.h"
#include "utils.h"
#include "mparser.h"
#include "interpret.h"
#include "runtime/files.h"
#include "call.h"

#ifdef MUME
#include "interact.h"
#include "invoke.h"

#include "def.files.h"
#include "struct.time.h"
#include "struct.player.h"
#include "struct.socket.h"
#include "model_mobile.h"
#include "callback.h"
#include "editor.h"
#include "pager.h"
#include "parser.h"
#include "utils.files.h"
#include "utils.gods.h"
#include "handler.char.h"

static void edit_ended(struct descriptor_data *d, char *fname, char *text)
{
  struct char_data *ch = d->character;

  if (text)
    if (!*text)         /* Empty text, delete file */
      {
      if (unlink(fname) == 0)
        cputs("Empty file, deleted.\n\r", ch);
      else
        cputs("Failed to delete an empty file - contact an implementor.\n\r", ch);
      }
}

static void view_ended(struct descriptor_data *d)
{
}

UNSAFEOP(fileedit, "s1 s2 -> . User edits file s1, description s2",
       2, (struct string *name, struct string *descr),
       OP_LEAF)
{
  TYPEIS(name, type_string);
  TYPEIS(descr, type_string);

  if (muduser && muduser->player && muduser->desc)
    fileedit(muduser, name->str, descr->str, edit_ended);
  undefined();
}

UNSAFEOP(fileview, "s -> . User views file s",
       1, (struct string *name),
       OP_LEAF)
{
  TYPEIS(name, type_string);

  if (muduser && muduser->player && muduser->desc)
    fileview(muduser->desc, name->str, view_ended);
  undefined();
}

static void mumedit_free(void *_data)
{
  struct dynpro *data = _data;

  undynpro(data);
  free(data);
}

static void mumedit_callback(void *_data, struct descriptor_data *d,
                       char *text, int len)
{
  struct string *mtext;
  struct gcpro gcpro1;
  struct character *who;
  value continuation;
  struct vector *args;
  struct session_context newp;

  if (text)
    {
      char *ntext = split_lines(text, len, "\n\r", TRUE);

      mtext = alloc_string(ntext);
      new_free(ntext);
    }
  else mtext = NULL;

  GCPRO1(mtext);
  who = char_mudlle(d->character);
  UNGCPRO();

  continuation = ((struct dynpro *)_data)->obj;
  mumedit_free(_data);
  session_start(&newp, 0, NULL, NULL, NULL);
  mcatch_call2(continuation, who, mtext);
  session_end();
}

TYPEDOP(textedit, "p s1 s2 n fn -> b. Have p edit text s1 (descr s2) with key n.\n\
Call fn(p, text) when the edit is done (text=null for cancel).\n\
Returns true if the edit could proceed, false if there was a key conflict",
      5, (struct character *who, struct string *text, struct string *descr,
          value key, value continuation),
      OP_LEAF | OP_NOESCAPE, "ossnf.n")
{
  struct dynpro *data;
  callback_t cb;

  TYPEIS(who, type_character);
  TYPEIS(text, type_string);
  TYPEIS(descr, type_string);
  ISINT(key);
  callable(continuation, 2);

  if (!CHAR_DESCRIPTOR(who->ch)) runtime_error(error_bad_value);

  data = xmalloc(sizeof *data);
  data->next = data->prev = NULL;
  dynpro(data, continuation);

  init_callback(cb, mumedit_callback, data, mumedit_free);
  if (edit(CHAR_DESCRIPTOR(who->ch), intval(key), text->str, string_len(text),
         descr->str, &cb))
    return makebool(TRUE);
  else
    {
      mumedit_free(data);
      return makebool(FALSE);
    }
}

static void mumeview_free(void *_data)
{
  struct dynpro *data = _data;

  undynpro(data);
  free(data);
}

static void mumeview_callback(void *_data, struct descriptor_data *d)
{
  struct character *who;
  value continuation;
  struct session_context newp;

  who = char_mudlle(d->character);
  continuation = ((struct dynpro *)_data)->obj;
  mumeview_free(_data);
  session_start(&newp, 0, NULL, NULL, NULL);
  mcatch_call1(continuation, who);
  session_end();
}

TYPEDOP(textview, "p s b fn -> . Have p view text s.\n\
If b is true use the user's preferred pager, otherwise use the simple one.\n\r\
Call fn(p) when the view is done",
      4, (struct character *who, struct string *text, value islong,
          value continuation),
      OP_LEAF | OP_NOESCAPE, "osnf.")
{
  struct dynpro *data;
  callback_t cb;

  TYPEIS(who, type_character);
  TYPEIS(text, type_string);
  callable(continuation, 1);

  if (!CHAR_DESCRIPTOR(who->ch)) runtime_error(error_bad_value);

  data = xmalloc(sizeof *data);
  data->next = data->prev = NULL;
  dynpro(data, continuation);

  init_callback(cb, mumeview_callback, data, mumeview_free);
  view_text(CHAR_DESCRIPTOR(who->ch), xstrdup(text->str), TRUE, istrue(islong), &cb);

  undefined();
}

static void program_ended(void *data, struct descriptor_data *who)
{
  struct session_context newp;

  session_start(&newp, 0, NULL, NULL, NULL);
  mcatch_call0(unprotect(data));
  session_end();
}

static void program_free(void *data)
{
  unprotect(data);
}

VAROP(start_process, "p s v1 v2 b fn -> . Execute program s with argv v1, envp v2. Call fn when it terminates. If b is true, make connection interactive",
       0)
{
  long i, argc, envc;
  char **argv_c, **envp_c;
  struct character *who;
  struct string *program;
  struct vector *argv, *envp;
  value interactive, cont;

  if (seclevel < LVL_IMPLEMENTOR) runtime_error(error_security_violation);
  if (nargs != 6) runtime_error(error_wrong_parameters);

  who = args->data[0];
  program = args->data[1];
  argv = args->data[2];
  envp = args->data[3];
  interactive = args->data[4];
  cont = args->data[5];

  TYPEIS(who, type_character);
  TYPEIS(program, type_string);
  TYPEIS(argv, type_vector);
  TYPEIS(envp, type_vector);
  callable(cont, 0);

  argc = vector_len(argv);
  if (argc < 1) runtime_error(error_bad_value);
  argv_c = alloca((argc + 1) * sizeof(char *));
  for (i = 0; i < argc; i++)
    {
      struct string *s = argv->data[i];

      TYPEIS(s, type_string);
      argv_c[i] = s->str;
    }
  argv_c[argc] = NULL;

  envc = vector_len(envp);
  envp_c = alloca((envc + 1) * sizeof(char *));
  for (i = 0; i < envc; i++)
    {
      struct string *s = envp->data[i];

      TYPEIS(s, type_string);
      envp_c[i] = s->str;
    }
  envp_c[envc] = NULL;

  if (who->ch->desc)
    {
      callback_t cb;

      init_callback(cb, program_ended, protect(cont), program_free);
      start_program(who->ch->desc, program->str, argv_c, envp_c,
                istrue(interactive), &cb);
    }
  undefined();
}
       

SECOP(basic_load, "s1 s2 n b1 -> b2. Loads file s1 (nice name s2) at security level n.n\
If b1 is false, libraries are not reloaded. True if successful",
      4, (struct string *name, struct string *nicename, value seclev, value reload),
      LVL_IMPLEMENTOR, 0)
{
  char *fname;
  long sl;

  TYPEIS(name, type_string);
  ISINT(seclev);
  sl = intval(seclev);
  if (sl < 0 || sl > LVL_IMPLEMENTOR) runtime_error(error_bad_value);

  LOCALSTR(fname, nicename);
  printf ("BASIC_LOAD %s, %s\n", name->str, fname); /* EDB */
  return makebool(load_file(name->str, fname, sl, istrue(reload)));
}

#else

OPERATION(load, "s -> . Loads file s", 1, (struct string *name), 0)
{
  TYPEIS(name, type_string);
  return makebool(load_file(name->str, name->str, 1, TRUE));
}

#endif


#ifndef _WIN32

UNSAFEOP(mkdir, "s n1 -> n2. Make directory s (mode n1)",
       2, (struct string *name, value mode),
       OP_LEAF | OP_NOALLOC)
{
  TYPEIS(name, type_string);
  ISINT(mode);

  return makeint(mkdir(name->str, intval(mode)));
}

UNSAFEOP(directory_files, "s -> l. List all files of directory s (returns false if problems)",
       1, (struct string *dir),
       OP_LEAF)
{
  DIR *d;

  TYPEIS(dir, type_string);
  printf ("WHAT THE? (EDB) %s\n", dir->str);

  if (d = opendir(dir->str))
    {
      struct dirent *entry;
      struct list *files = NULL;
      struct gcpro gcpro1;

      GCPRO1(files);
      while (entry = readdir(d))
      {
        struct string *fname = alloc_string(entry->d_name);

        files = alloc_list(fname, files);
      }
      UNGCPRO();
      closedir(d);

      return files;
    }
  return makebool(FALSE);       
}

UNSAFEOP(file_stat, "s -> v. Returns status of file s (returns false for failure)",
       1, (struct string *fname),
       OP_LEAF)
{
  struct stat sb;

  TYPEIS(fname, type_string);
  if (!stat(fname->str, &sb))
    {
      struct vector *info = alloc_vector(13);

      info->data[0] = makeint(sb.st_dev);
      info->data[1] = makeint(sb.st_ino);
      info->data[2] = makeint(sb.st_mode);
      info->data[3] = makeint(sb.st_nlink);
      info->data[4] = makeint(sb.st_uid);
      info->data[5] = makeint(sb.st_gid);
      info->data[6] = makeint(sb.st_rdev);
      info->data[7] = makeint(sb.st_size);
      info->data[8] = makeint(sb.st_atime);
      info->data[9] = makeint(sb.st_mtime);
      info->data[10] = makeint(sb.st_ctime);
      info->data[11] = makeint(sb.st_blksize);
      info->data[12] = makeint(sb.st_blocks);

      return info;
    }
  return makebool(FALSE);
}

UNSAFEOP(remove, "s -> b. Removes file s, returns TRUE if success",
        1, (struct string *fname),
        OP_LEAF)
{
  TYPEIS(fname, type_string);

  return makebool(unlink(fname->str) == 0);
}

UNSAFEOP(read_file, "s1 -> s2. Reads file s1 and returns its contents (or the Unix errno value)",
        1, (struct string *name),
        OP_LEAF)
{
  int fd;

  TYPEIS(name, type_string);

  printf ("READ FILE: %s\n", name->str);

  if ((fd = open(name->str, O_RDONLY)) >= 0)
    {
      off_t size = lseek(fd, 0, SEEK_END);

      if (size >= 0)
      {
        struct string *s = (struct string *)allocate_string(type_string, size + 1);

        if (lseek(fd, 0, SEEK_SET) == 0 && read(fd, s->str, size) == size)
          {
            s->str[size] = '\0';
            close(fd);
            return s;
          }
      }
      close(fd);
    }
  return makeint(errno);
}

UNSAFEOP(string_write, "s1 s2 -> n. Appends string s2 to file s1. Creates s1 if nonexistent.\n\r\
Returns the unix error number for failure, 0 for success.",
       2, (struct string *file, struct string *val), 
       OP_LEAF | OP_NOESCAPE)
{
  int fd, ok;
  unsigned long size;

  TYPEIS(file, type_string);
  TYPEIS(val, type_string);

  printf ("string_write: %s\n", file->str); /* EDB */
  fd = open(file->str, O_WRONLY | O_CREAT | O_APPEND, 0666);
  if (fd > 0 && fchmod(fd, 0666) == 0)
    {
      size = strlen(val->str);
      if (write(fd, val->str, size) == size &&
        close(fd) == 0)
      return makeint(0);
    }
  return makeint(errno);
}
#endif // not defined WIN32

void files_init(void)
{
#ifdef MUME
  DEFINE("textedit", textedit);
  DEFINE("textview", textview);
  DEFINE("fileedit", fileedit);
  DEFINE("fileview", fileview);
  DEFINE("start_process", start_process);
  DEFINE("basic_load", basic_load);
#else
  DEFINE("load", load);
#endif
#ifndef _WIN32
  DEFINE("string_write", string_write);
  DEFINE("string_read", read_file);
  DEFINE("mkdir", mkdir);
  DEFINE("directory_files", directory_files);
  DEFINE("file_stat", file_stat);
  DEFINE("remove", remove);
#endif
}

Generated by  Doxygen 1.6.0   Back to index