Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

new module



-----BEGIN PGP SIGNED MESSAGE-----

Here's a useful module.  It implements the most basic file-manipulation
commands.  (I could have used this last week, when I filled up the
process table and needed to remove a file in order to unfill it.)

Zoltan, why does addbuiltin() not allow the funcid and defopts members of
the builtin structure to be set?  They would be helpful in implementing
mv in this module.

 -zefram

      Index: Src/Modules/Makefile.in
      ===================================================================
      RCS file: /home/zefram/usr/cvsroot/zsh/Src/Modules/Makefile.in,v
      retrieving revision 1.3
      diff -c -r1.3 Makefile.in
      *** Src/Modules/Makefile.in	1996/12/23 02:34:09	1.3
      --- Src/Modules/Makefile.in	1996/12/23 02:40:44
      ***************
      *** 86,95 ****
        	$(SED) -n -f $(srcdir)/../makepro.sed $< > $@
        
        # generated prototypes
      ! PROTO = example.pro
        
        # target modules
      ! MODULES = example.so
        
        # ========= DEPENDENCIES FOR BUILDING ==========
        
      --- 86,95 ----
        	$(SED) -n -f $(srcdir)/../makepro.sed $< > $@
        
        # generated prototypes
      ! PROTO = example.pro files.pro
        
        # target modules
      ! MODULES = example.so files.so
        
        # ========= DEPENDENCIES FOR BUILDING ==========
        
      Index: Src/Modules/files.c
      ===================================================================
      RCS file: files.c
      diff -N files.c
      *** ..................../dev/null	Thu Sep  7 20:04:30 1995
      --- Src/Modules/files.c	Mon Dec 23 06:07:44 1996
      ***************
      *** 0 ****
      --- 1,466 ----
      + /*
      +  * $Id$
      +  *
      +  * files.c - file operation builtins
      +  *
      +  * This file is part of zsh, the Z shell.
      +  *
      +  * Copyright (c) 1996 Andrew Main
      +  * 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 its documentation 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 Andrew Main 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 Andrew Main and the Zsh Development Group have been advised of
      +  * the possibility of such damage.
      +  *
      +  * Andrew Main 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 Andrew Main and the
      +  * Zsh Development Group have no obligation to provide maintenance,
      +  * support, updates, enhancements, or modifications.
      +  *
      +  */
      + 
      + #include "zsh.h"
      + 
      + typedef int (*MoveFunc) _((char const *, char const *));
      + 
      + #include "files.pro"
      + 
      + static char buf[PATH_MAX * 2];
      + static char rbuf[PATH_MAX];
      + 
      + /**/
      + static int
      + ask(void)
      + {
      +     int a = getchar(), c;
      +     for(c = a; c != EOF && c != '\n'; )
      + 	c = getchar();
      +     return a == 'y' || a == 'Y';
      + }
      + 
      + /* sync builtin */
      + 
      + /**/
      + static int
      + bin_sync(char *nam, char **args, char *ops, int func)
      + {
      +     sync();
      +     return 0;
      + }
      + 
      + /* mkdir builtin */
      + 
      + /**/
      + static int
      + bin_mkdir(char *nam, char **args, char *ops, int func)
      + {
      +     mode_t oumask = umask(0);
      +     mode_t mode = 0777 & ~oumask;
      +     int err = 0;
      + 
      +     umask(oumask);
      +     if(ops['m']) {
      + 	char *str = *args++, *ptr;
      + 
      + 	if(!*args) {
      + 	    zwarnnam(nam, "not enough arguments", NULL, 0);
      + 	    return 1;
      + 	}
      + 	mode = zstrtol(str, &ptr, 8);
      + 	if(!*str || *ptr) {
      + 	    zwarnnam(nam, "invalid mode `%s'", str, 0);
      + 	    return 1;
      + 	}
      +     }
      +     for(; *args; args++) {
      + 	char *ptr = strchr(*args, 0);
      + 
      + 	while(ptr > *args + (**args == '/') && *--ptr == '/')
      + 	    *ptr = 0;
      + 	if(ztrlen(*args) > PATH_MAX - 1) {
      + 	    zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
      + 	    err = 1;
      + 	    continue;
      + 	}
      + 	if(ops['p']) {
      + 	    char *ptr = *args;
      + 
      + 	    for(;;) {
      + 		while(*ptr == '/')
      + 		    ptr++;
      + 		while(*ptr && *ptr != '/')
      + 		    ptr++;
      + 		if(!*ptr) {
      + 		    err |= domkdir(nam, *args, mode, 1);
      + 		    break;
      + 		} else {
      + 		    int e;
      + 
      + 		    *ptr = 0;
      + 		    e = domkdir(nam, *args, mode | 0300, 1);
      + 		    if(e) {
      + 			err = 1;
      + 			break;
      + 		    }
      + 		    *ptr = '/';
      + 		}
      + 	    }
      + 	} else
      + 	    err |= domkdir(nam, *args, mode, 0);
      +     }
      +     return err;
      + }
      + 
      + /**/
      + static int
      + domkdir(char *nam, char *path, mode_t mode, int p)
      + {
      +     int err;
      +     mode_t oumask;
      +     char const *rpath = unmeta(path);
      + 
      +     if(p) {
      + 	struct stat st;
      + 
      + 	if(!stat(rpath, &st) && S_ISDIR(st.st_mode))
      + 	    return 0;
      +     }
      +     oumask = umask(0);
      +     err = mkdir(path, mode) ? errno : 0;
      +     umask(oumask);
      +     if(!err)
      + 	return 0;
      +     zwarnnam(nam, "cannot make directory `%s': %e", path, err);
      +     return 1;
      + }
      + 
      + /* rmdir builtin */
      + 
      + /**/
      + static int
      + bin_rmdir(char *nam, char **args, char *ops, int func)
      + {
      +     int err = 0;
      + 
      +     for(; *args; args++) {
      + 	char *rpath = unmeta(*args);
      + 
      + 	if(!rpath) {
      + 	    zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
      + 	    err = 1;
      + 	} else if(rmdir(rpath)) {
      + 	    zwarnnam(nam, "cannot remove directory `%s': %e", *args, errno);
      + 	    err = 1;
      + 	}
      +     }
      +     return err;
      + }
      + 
      + /* ln and mv builtins */
      + 
      + #define BIN_LN 0
      + #define BIN_MV 1
      + 
      + #define MV_NODIRS (1<<0)
      + #define MV_FORCE  (1<<1)
      + #define MV_INTER  (1<<2)
      + #define MV_ASKNW  (1<<3)
      + 
      + /* bin_ln actually does three related jobs: hard linking, symbolic *
      +  * linking, and renaming.  If called as mv it renames, otherwise   *
      +  * it looks at the -s option.  If hard linking, it will refuse to  *
      +  * attempt linking to a directory unless the -d option is given.   */
      + 
      + /**/
      + static int
      + bin_ln(char *nam, char **args, char *ops, int func)
      + {
      +     MoveFunc move;
      +     int flags, space, err = 0;
      +     char **a, *ptr, *rp;
      +     struct stat st;
      + 
      +     if(func == BIN_MV) {
      + 	move = rename;
      + 	flags = ops['f'] ? 0 : MV_ASKNW;
      +     } else {
      + 	flags = ops['f'] ? MV_FORCE : 0;
      + #ifdef HAVE_LSTAT
      + 	if(ops['s'])
      + 	    move = symlink;
      + 	else
      + #endif
      + 	     {
      + 	    move = link;
      + 	    if(!ops['d'])
      + 		flags |= MV_NODIRS;
      + 	}
      +     }
      +     if(ops['i'])
      + 	flags |= MV_INTER;
      +     for(a = args; a[1]; a++) ;
      +     if(a != args) {
      + 	rp = unmeta(*a);
      + 	if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode))
      + 	    goto havedir;
      +     }
      +     if(a > args+1) {
      + 	zwarnnam(nam, "last of many arguments must be a directory", NULL, 0);
      + 	return 1;
      +     }
      +     if(!args[1]) {
      + 	ptr = strrchr(args[0], '/');
      + 	if(ptr)
      + 	    args[1] = ptr+1;
      + 	else
      + 	    args[1] = args[0];
      +     }
      +     return domove(nam, move, args[0], args[1], flags);
      +     havedir:
      +     strcpy(buf, *a);
      +     *a = NULL;
      +     space = PATH_MAX - 2 - ztrlen(buf);
      +     rp = strchr(buf, 0);
      +     *rp++ = '/';
      +     for(; *args; args++) {
      + 	if(ztrlen(*args) > PATH_MAX - 1) {
      + 	    zwarnnam(nam, "%s: %e", *args, ENAMETOOLONG);
      + 	    err = 1;
      + 	    continue;
      + 	}
      + 	ptr = strrchr(*args, '/');
      + 	if(ptr)
      + 	    ptr++;
      + 	else
      + 	    ptr = *args;
      + 	if(ztrlen(ptr) > space) {
      + 	    zwarnnam(nam, "%s: %e", ptr, ENAMETOOLONG);
      + 	    err = 1;
      + 	    continue;
      + 	}
      + 	strcpy(rp, ptr);
      + 	err |= domove(nam, move, *args, buf, flags);
      +     }
      +     return err;
      + }
      + 
      + /**/
      + static int
      + domove(char *nam, MoveFunc move, char *p, char *q, int flags)
      + {
      +     struct stat st;
      +     char *qbuf;
      +     strcpy(rbuf, unmeta(p));
      +     qbuf = unmeta(q);
      +     /***/fprintf(stderr, "`%s' -> `%s'\n", rbuf, qbuf);
      +     if(flags & MV_NODIRS) {
      + 	errno = EISDIR;
      + 	if(lstat(rbuf, &st) || S_ISDIR(st.st_mode)) {
      + 	    zwarnnam(nam, "%s: %e", p, errno);
      + 	    return 1;
      + 	}
      +     }
      +     if(!lstat(qbuf, &st)) {
      + 	if(S_ISDIR(st.st_mode)) {
      + 	    zwarnnam(nam, "%s: cannot overwrite directory", q, 0);
      + 	    return 1;
      + 	} else if(flags & MV_INTER) {
      + 	    nicezputs(nam, stderr);
      + 	    fputs(": replace `", stderr);
      + 	    nicezputs(q, stderr);
      + 	    fputs("'? ", stderr);
      + 	    fflush(stderr);
      + 	    if(!ask())
      + 		return 0;
      + 	} else if((flags & MV_ASKNW) & access(qbuf, W_OK)) {
      + 	    nicezputs(nam, stderr);
      + 	    fputs(": replace `", stderr);
      + 	    nicezputs(q, stderr);
      + 	    fprintf(stderr, "', overriding mode %04o? ", st.st_mode & 07777);
      + 	    fflush(stderr);
      + 	    if(!ask())
      + 		return 0;
      + 	}
      + 	if(flags & MV_FORCE)
      + 	    unlink(qbuf);
      +     }
      +     if(move(rbuf, qbuf)) {
      + 	zwarnnam(nam, "%s: %e", p, errno);
      + 	return 1;
      +     }
      +     return 0;
      + }
      + 
      + /**/
      + static int
      + bin_mv(char *nam, char **args, char *ops, int func)
      + {
      +     return bin_ln(nam, args, ops, BIN_MV);
      + }
      + 
      + /* rm builtin */
      + 
      + /**/
      + static int
      + bin_rm(char *nam, char **args, char *ops, int func)
      + {
      +     int err = 0;
      + 
      +     for(; *args; args++)
      + 	err |= dorm(nam, *args, ops);
      +     return ops['f'] ? 0 : err;
      + }
      + 
      + /**/
      + static int
      + dorm(char *nam, char *arg, char *ops)
      + {
      +     struct stat st;
      +     char *rp = unmeta(arg);
      + 
      +     if(!rp) {
      + 	if(!ops['f'])
      + 	    zwarnnam(nam, "%s: %e", arg, ENAMETOOLONG);
      + 	return 1;
      +     }
      +     if((!ops['d'] || !ops['f']) && !stat(rp, &st)) {
      + 	if(!ops['d'] && S_ISDIR(st.st_mode)) {
      + 	    if(ops['r']) {
      + 		DIR *d;
      + 		char *pos, *fn;
      + 		int err = 0, space;
      + 		d = opendir(rp);
      + 		if(!d) {
      + 		    if(!ops['f'])
      + 			zwarnnam(nam, "%s: %e", arg, errno);
      + 		    return 1;
      + 		}
      + 		if(arg != buf)
      + 		    strcpy(buf, arg);
      + 		space = PATH_MAX - 2 - ztrlen(buf);
      + 		pos = strchr(buf, 0);
      + 		*pos++ = '/';
      + 		while((fn = zreaddir(d, 1))) {
      + 		    if(ztrlen(fn) > space) {
      + 			pos[-1] = 0;
      + 			zwarnnam(nam, "%s: %e", buf, ENAMETOOLONG);
      + 			err = 1;
      + 			continue;
      + 		    }
      + 		    strcpy(pos, fn);
      + 		    err |= dorm(nam, buf, ops);
      + 		}
      + 		closedir(d);
      + 		pos[-1] = 0;
      + 		if(!ops['f'] && ops['i']) {
      + 		    nicezputs(nam, stderr);
      + 		    fputs(": remove `", stderr);
      + 		    nicezputs(buf, stderr);
      + 		    fputs("'? ", stderr);
      + 		    fflush(stderr);
      + 		    if(!ask())
      + 			return err;
      + 		}
      + 		if(!rmdir(unmeta(buf)))
      + 		    return err;
      + 		if(!ops['f'])
      + 		    zwarnnam(nam, "%s: %e", buf, errno);
      + 		return 1;
      + 	    }
      + 	    if(!ops['f'])
      + 		zwarnnam(nam, "%s: %e", arg, EISDIR);
      + 	    return 1;
      + 	}
      + 	if(!ops['f'] && ops['i']) {
      + 	    nicezputs(nam, stderr);
      + 	    fputs(": remove `", stderr);
      + 	    nicezputs(arg, stderr);
      + 	    fputs("'? ", stderr);
      + 	    fflush(stderr);
      + 	    if(!ask())
      + 		return 0;
      + 	} else if(!ops['f'] && access(rp, W_OK)) {
      + 	    nicezputs(nam, stderr);
      + 	    fputs(": remove `", stderr);
      + 	    nicezputs(arg, stderr);
      + 	    fprintf(stderr, "', overriding mode %04o? ", st.st_mode & 07777);
      + 	    fflush(stderr);
      + 	    if(!ask())
      + 		return 0;
      + 	}
      +     }
      +     if(!unlink(rp))
      + 	return 0;
      +     if(!ops['f'])
      + 	zwarnnam(nam, "%s: %e", arg, errno);
      +     return 1;
      + }
      + 
      + /* module paraphernalia */
      + 
      + static struct bin {
      +     char *name;
      +     int binf;
      +     HandlerFunc func;
      +     int min, max;
      +     char *optstr;
      +     int added;
      + } bins[] = {
      + #ifdef HAVE_LSTAT
      +     { "ln",    0, bin_ln,    1, -1, "dfis", 0 },
      + #else
      +     { "ln",    0, bin_ln,    1, -1, "dfi",  0 },
      + #endif
      +     { "mkdir", 0, bin_mkdir, 1, -1, "pm",   0 },
      +     { "mv",    0, bin_mv,    2, -1, "fi",   0 },
      +     { "rm",    0, bin_rm,    1, -1, "dfir", 0 },
      +     { "rmdir", 0, bin_rmdir, 1, -1, NULL,   0 },
      +     { "sync",  0, bin_sync,  0,  0, NULL,   0 },
      +     { NULL, 0, NULL, 0, 0, NULL, 0 }
      + };
      + 
      + /**/
      + int
      + boot_files(Module m)
      + {
      +     int added = 0;
      +     struct bin *bin;
      + 
      +     for(bin = bins; bin->name; bin++) {
      + 	if (!bin->added && addbuiltin(bin->name, bin->binf, bin->func,
      + 	    bin->min, bin->max, bin->optstr))
      + 	    zwarnnam(m->nam, "name clash when adding builtin `%s'",
      + 		bin->name, 0);
      + 	else
      + 	    added = bin->added = 1;
      +     }
      +     return !added;
      + }
      + 
      + #ifdef MODULE
      + 
      + /**/
      + int
      + cleanup_files(Module m)
      + {
      +     int fail;
      +     struct bin *bin;
      + 
      +     for(bin = bins; bin->name; bin++)
      + 	if (bin->added && deletebuiltin(bin->name))
      + 	    fail = 1;
      + 	else
      + 	    bin->added = 0;
      +     return fail;
      + }
      + #endif

-----BEGIN PGP SIGNATURE-----
Version: 2.6.2

iQCVAwUBMr7DD3D/+HJTpU/hAQEvbAP+MCGdCfA11nu9vmJXk6wLQbCpUVnTm8k4
dGG8FW/CX+CQzJ48qGTRcFeG/c9cMlC6foBh3Lg4IeONFY3gs3aLOr2LBpLp9ZXz
XV/xJAmN2cShm48KG+zaMwGs6ZCbwr5k797SscZ0ZD+cBrX38WM3QP1NY6ByaTMt
awSnQsfUgYM=
=9Scr
-----END PGP SIGNATURE-----



Messages sorted by: Reverse Date, Date, Thread, Author