1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-01-01 05:16:05 +01:00

Initial revision

This commit is contained in:
Tanaka Akira 1999-05-31 17:10:16 +00:00
parent ba1bd66d5f
commit b39cafaa22
5 changed files with 498 additions and 0 deletions

0
Config/.cvsignore Normal file
View file

80
Config/defs.mk.in Normal file
View file

@ -0,0 +1,80 @@
#
# Basic Makefile definitions
#
# Copyright (c) 1995-1997 Richard Coleman
# All rights reserved.
#
# Permission is hereby granted, without written agreement and without
# license or royalty fees, to use, copy, modify, and distribute this
# software and to distribute modified versions of this software for any
# purpose, provided that the above copyright notice and the following
# two paragraphs appear in all copies of this software.
#
# In no event shall Richard Coleman or the Zsh Development Group be liable
# to any party for direct, indirect, special, incidental, or consequential
# damages arising out of the use of this software and its documentation,
# even if Richard Coleman and the Zsh Development Group have been advised of
# the possibility of such damage.
#
# Richard Coleman and the Zsh Development Group specifically disclaim any
# warranties, including, but not limited to, the implied warranties of
# merchantability and fitness for a particular purpose. The software
# provided hereunder is on an "as is" basis, and Richard Coleman and the
# Zsh Development Group have no obligation to provide maintenance,
# support, updates, enhancements, or modifications.
#
# fundamentals
SHELL = /bin/sh
@SET_MAKE@
# installation directories
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
libdir = @libdir@
MODDIR = $(libdir)/zsh/$(VERSION)
infodir = @infodir@
mandir = @mandir@
# compilation
CC = @CC@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
DEFS = @DEFS@
CFLAGS = @CFLAGS@
LDFLAGS = @LDFLAGS@
EXTRA_LDFLAGS = @EXTRA_LDFLAGS@
DLCFLAGS = @DLCFLAGS@
DLLDFLAGS = @DLLDFLAGS@
LIBLDFLAGS = @LIBLDFLAGS@
EXELDFLAGS = @EXELDFLAGS@
LIBS = @LIBS@
DL_EXT = @DL_EXT@
DLLD = @DLLD@
EXPOPT = @EXPOPT@
IMPOPT = @IMPOPT@
# utilities
AWK = @AWK@
YODL = @YODL@
YODL2TXT = $(YODL)2txt
YODL2HTML = $(YODL)2html
# install utility
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
# flags passed to recursive makes in subdirectories
MAKEDEFS = \
prefix='$(prefix)' exec_prefix='$(exec_prefix)' bindir='$(bindir)' \
libdir='$(libdir)' MODDIR='$(MODDIR)' infodir='$(infodir)' mandir='$(mandir)' \
CC='$(CC)' CPPFLAGS='$(CPPFLAGS)' DEFS='$(DEFS)' CFLAGS='$(CFLAGS)' \
LDFLAGS='$(LDFLAGS)' EXTRA_LDFLAGS='$(EXTRA_LDFLAGS)' \
DLCFLAGS='$(DLCFLAGS)' DLLDFLAGS='$(DLLDFLAGS)' \
LIBLDFLAGS='$(LIBLDFLAGS)' EXELDFLAGS='$(EXELDFLAGS)' \
LIBS='$(LIBS)' DL_EXT='$(DL_EXT)' DLLD='$(DLLD)' \
AWK='$(AWK)' YODL='$(YODL)' YODL2TXT='$(YODL2TXT)' YODL2HTML='$(YODL2HTML)'
# override built-in suffix list
.SUFFIXES:

46
Doc/Zsh/mod_mapfile.yo Normal file
View file

@ -0,0 +1,46 @@
texinode(The mapfile Module)(The parameter Module)(The files Module)(Zsh Modules)
sect(The mapfile Module)
cindex(parameter, file access via)
The tt(mapfile) module provides one special associative array parameter of
the same name.
startitem()
vindex(mapfile)
item(tt(mapfile))(
This associative array takes as keys the names of files; the resulting
value is the content of the file. The value is treated identically to any
other text coming from a parameter. The value may also be assigned to, in
which case the file in question is written (whether or not it originally
existed); or an element may be unset, which will delete the file in
question. For example, `tt(vared mapfile[myfile])' works as expected,
editing the file `tt(myfile)'.
When the array is accessed as a whole, the keys are the names of files in
the current directory, and the values are empty (to save a huge overhead in
memory). Thus tt(${(k)mapfile}) has the same affect as the glob operator
tt(*(D)), since files beginning with a dot are not special. Care must be
taken with expressions such as tt(rm ${(k)mapfile}), which will delete
every file in the current directory without the usual `tt(rm *)' test.
The parameter tt(mapfile) may be made read-only; in that case, files
referenced may not be written or deleted.
)
enditem()
subsect(Limitations)
Although reading and writing of the file in question is efficiently
handled, zsh's internal memory management may be arbitrarily baroque. Thus
it should not automatically be assumed that use of tt(mapfile) represents a
gain in efficiency over use of other mechanisms. Note in particular that
the whole contents of the file will always reside physically in memory when
accessed (possibly multiple times, due to standard parameter subsitution
operations).
No errors are printed or flagged for non-existent, unreadable, or
unwriteable files, as the parameter mechanism is too low in the shell
execution hierarchy to make this convenient.
It is unfortunate that the mechanism for loading modules does not yet allow
the user to specify the name of the shell parameter to be given the special
behaviour.

369
Src/Modules/mapfile.c Normal file
View file

@ -0,0 +1,369 @@
/*
* mapfile.c - associative array interface to external files
*
* This file is part of zsh, the Z shell.
*
* Copyright (c) 1999 Sven Wischnowsky, Peter Stephenson
* All rights reserved.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and to distribute modified versions of this software for any
* purpose, provided that the above copyright notice and the following
* two paragraphs appear in all copies of this software.
*
* In no event shall Sven Wischnowsky, Peter Stephenson or the Zsh Development
* Group be liable to any party for direct, indirect, special, incidental, or
* consequential damages arising out of the use of this software and its
* documentation, even if Peter Stephenson, Sven Wischnowsky and the Zsh
* Development Group have been advised of the possibility of such damage.
*
* Peter Stephenson, Sven Wischnowsky and the Zsh Development Group
* specifically disclaim any warranties, including, but not limited to, the
* implied warranties of merchantability and fitness for a particular purpose.
* The softwareprovided hereunder is on an "as is" basis, and Peter
* Stephenson, Sven Wischnowsky and the Zsh Development Group have no
* obligation to provide maintenance, support, updates, enhancements, or
* modifications.
*
*/
/*
* To do: worry about when keys of associative arrays get unmeta'd.
*/
#include "mapfile.mdh"
#include "mapfile.pro"
/*
* Make sure we have all the bits I'm using for memory mapping, otherwise
* I don't know what I'm doing.
*/
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_FTRUNCATE)
#if defined(HAVE_MMAP) && defined(HAVE_MUNMAP) && defined(HAVE_MSYNC)
#define USE_MMAP 1
#include <sys/mman.h>
#if !defined(MAP_VARIABLE)
#define MAP_VARIABLE 0
#endif
#if !defined(MAP_FILE)
#define MAP_FILE 0
#endif
#if !defined(MAP_NORESERVE)
#define MAP_NORESERVE 0
#endif
#define MMAP_ARGS (MAP_FILE | MAP_VARIABLE | MAP_SHARED | MAP_NORESERVE)
#endif /* HAVE_MMAP && HAVE_MUNMAP && HAVE_MSYNC */
#endif /* HAVE_SYS_MMAN_H && HAVE_FTRUNCATE */
/*
* Name of the special parameter. If zmodload took arguments,
* we could make this selectable.
*/
static char mapfile_nam[] = "mapfile";
static Param mapfile_pm;
/* Empty dummy function for special hash parameters. */
/**/
static void
shempty(void)
{
}
/* Create the special hash parameter. */
/**/
static Param
createmapfilehash()
{
Param pm;
HashTable ht;
unsetparam(mapfile_nam);
mapfile_pm = NULL;
if (!(pm = createparam(mapfile_nam, PM_SPECIAL|PM_REMOVABLE|PM_HASHED)))
return NULL;
pm->level = pm->old ? locallevel : 0;
pm->gets.hfn = hashgetfn;
pm->sets.hfn = setpmmapfiles;
pm->unsetfn = stdunsetfn;
pm->u.hash = ht = newhashtable(7, mapfile_nam, NULL);
ht->hash = hasher;
ht->emptytable = (TableFunc) shempty;
ht->filltable = NULL;
ht->addnode = (AddNodeFunc) shempty;
ht->getnode = ht->getnode2 = getpmmapfile;
ht->removenode = (RemoveNodeFunc) shempty;
ht->disablenode = NULL;
ht->enablenode = NULL;
ht->freenode = (FreeNodeFunc) shempty;
ht->printnode = printparamnode;
ht->scantab = scanpmmapfile;
return (mapfile_pm = pm);
}
/* Functions for the options special parameter. */
/**/
static void
setpmmapfile(Param pm, char *value)
{
int fd = -1, len;
char *name = ztrdup(pm->nam);
#ifdef USE_MMAP
caddr_t mmptr;
#else
FILE *fout;
#endif
/*
* First unmetafy the value, and the name since we don't
* where it's been.
*/
unmetafy(name, &len);
unmetafy(value, &len);
/* Open the file for writing */
#ifdef USE_MMAP
if (!(pm->flags & PM_READONLY) &&
(fd = open(name, O_RDWR|O_CREAT|O_NOCTTY, 0666)) >= 0 &&
(mmptr = (caddr_t)mmap((caddr_t)0, len, PROT_READ | PROT_WRITE,
MMAP_ARGS, fd, (off_t)0)) != (caddr_t)-1) {
/*
* First we need to make sure the file is long enough for
* when we msync. On AIX, at least, we just get zeroes otherwise.
*/
ftruncate(fd, len);
memcpy(mmptr, value, len);
msync(mmptr, len, MS_SYNC);
/*
* Then we need to truncate again, since mmap() always maps complete
* pages. Honestly, I tried it without, and you need both.
*/
ftruncate(fd, len);
}
#else /* don't USE_MMAP */
/* can't be bothered to do anything too clever here */
if ((fout = fopen(name, "w"))) {
while (len--)
putc(*value++, fout);
fclose(fout);
}
#endif /* USE_MMAP */
if (fd >= 0)
close(fd);
free(name);
free(value);
}
/**/
static void
unsetpmmapfile(Param pm, int exp)
{
/* Unlink the file given by pm->nam */
char *fname = ztrdup(pm->nam);
int dummy;
unmetafy(fname, &dummy);
if (!(pm->flags & PM_READONLY))
unlink(fname);
free(fname);
}
/**/
static void
setpmmapfiles(Param pm, HashTable ht)
{
int i;
HashNode hn;
/* just to see if I've understood what's happening */
DPUTS(pm != mapfile_pm, "BUG: setpmmapfiles called for wrong param");
if (!ht)
return;
if (!(pm->flags & PM_READONLY))
for (i = 0; i < ht->hsize; i++)
for (hn = ht->nodes[i]; hn; hn = hn->next) {
struct value v;
v.isarr = v.inv = v.a = 0;
v.b = -1;
v.arr = NULL;
v.pm = (Param) hn;
setpmmapfile(v.pm, ztrdup(getstrvalue(&v)));
}
deleteparamtable(ht);
}
/**/
static char *
get_contents(char *fname)
{
int fd;
#ifdef USE_MMAP
caddr_t mmptr;
struct stat sbuf;
#endif
char *val;
unmetafy(fname = ztrdup(fname), &fd);
#ifdef USE_MMAP
if ((fd = open(fname, O_RDONLY | O_NOCTTY)) < 0 ||
fstat(fd, &sbuf) ||
(mmptr = (caddr_t)mmap((caddr_t)0, sbuf.st_size, PROT_READ,
MMAP_ARGS, fd, (off_t)0)) == (caddr_t)-1) {
if (fd >= 0)
close(fd);
free(fname);
return NULL;
}
/*
* Sadly, we need to copy the thing even if metafying doesn't
* change it. We just don't know when we might get a chance to
* munmap it, otherwise.
*/
val = metafy((char *)mmptr, sbuf.st_size, META_HEAPDUP);
munmap(mmptr, sbuf.st_size);
close(fd);
#else /* don't USE_MMAP */
val = NULL;
if ((fd = open(fname, O_RDONLY | O_NOCTTY)) >= 0) {
LinkList ll;
MUSTUSEHEAP("mapfile:get_contents");
if ((ll = readoutput(fd, 1)))
val = peekfirst(ll);
}
#endif /* USE_MMAP */
free(fname);
return val;
}
/**/
static HashNode
getpmmapfile(HashTable ht, char *name)
{
char *contents;
Param pm = NULL;
HEAPALLOC {
pm = (Param) zhalloc(sizeof(struct param));
pm->nam = dupstring(name);
pm->flags = PM_SCALAR;
pm->sets.cfn = setpmmapfile;
pm->gets.cfn = strgetfn;
pm->unsetfn = unsetpmmapfile;
pm->ct = 0;
pm->env = NULL;
pm->ename = NULL;
pm->old = NULL;
pm->level = 0;
pm->flags |= (mapfile_pm->flags & PM_READONLY);
/* Set u.str to contents of file given by name */
if ((contents = get_contents(pm->nam)))
pm->u.str = contents;
else {
pm->u.str = "";
pm->flags |= PM_UNSET;
}
} LASTALLOC;
return (HashNode) pm;
}
/**/
static void
scanpmmapfile(HashTable ht, ScanFunc func, int flags)
{
struct param pm;
DIR *dir;
if (!(dir = opendir(".")))
return;
pm.flags = PM_SCALAR;
pm.sets.cfn = setpmmapfile;
pm.gets.cfn = strgetfn;
pm.unsetfn = unsetpmmapfile;
pm.ct = 0;
pm.env = NULL;
pm.ename = NULL;
pm.old = NULL;
pm.level = 0;
pm.flags |= (mapfile_pm->flags & PM_READONLY);
/* Here we scan the current directory, calling func() for each file */
while ((pm.nam = zreaddir(dir, 1))) {
/*
* Hmmm, it's rather wasteful always to read the contents.
* In fact, it's grotesequely wasteful, since that would mean
* we always read the entire contents of every single file
* in the directory into memory. Hence just leave it empty.
*/
pm.u.str = "";
func((HashNode) &pm, flags);
}
closedir(dir);
}
/**/
int
setup_mapfile(Module m)
{
return 0;
}
/**/
int
boot_mapfile(Module m)
{
/* Create the special associative array. */
if (!createmapfilehash())
return 1;
return 0;
}
#ifdef MODULE
/**/
int
cleanup_mapfile(Module m)
{
Param pm;
/* Remove the special parameter if it is still the same. */
if ((pm = (Param) paramtab->getnode(paramtab, mapfile_nam)) &&
pm == mapfile_pm) {
pm->flags &= ~PM_READONLY;
unsetparam_pm(pm, 0, 1);
}
return 0;
}
/**/
int
finish_mapfile(Module m)
{
return 0;
}
#endif

3
Src/Modules/mapfile.mdd Normal file
View file

@ -0,0 +1,3 @@
autoparams="mapfile"
objects="mapfile.o"