home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright (c) 1986, 1990 by The Trustees of Columbia University in
- the City of New York. Permission is granted to any individual or
- institution to use, copy, or redistribute this software so long as it
- is not sold for profit, provided this copyright notice is retained.
-
- Author: Howie Kaye
- */
-
- #define GRPERR
-
- /*
- * ccmd group name parser.
- */
-
- #if unix
- #include "ccmdlib.h"
- #include "cmfncs.h"
- #include "cmgrp.h"
-
- #define INCGRPS 100
-
- char *malloc(), realloc();
- static brktab grpbrk = { /* all valid chars for grp */
- { /* alphanums, "~#/_-\[]," */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
- 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
- },
- {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x3f,
- 0x80, 0x00, 0x00, 0x1e, 0x80, 0x00, 0x00, 0x1f,
- },
- };
-
- struct group **buildgrouplist();
- int grpparse(), grphelp(), grpcomplete();
- ftspec ft_grp = { grpparse, grphelp, grpcomplete, 0, &grpbrk };
-
- /*
- * parse routine for group names.
- */
- PASSEDSTATIC int
- grpparse(text, textlen, fdbp, parselen, value)
- char *text;
- int textlen, *parselen;
- fdb *fdbp;
- pval *value;
- {
- static struct grp **g;
- char *term;
- int pmatch, ematch,i;
-
- match(text, textlen, fdbp, &g, &term, &pmatch, &ematch); /* find matches */
-
- if (pmatch == 0) /* no partial matches. */
- return(GRPxNM); /* then no matches */
-
- if (term == NULL) /* unterminated....not done */
- return(CMxINC); /* return incompleteness */
-
- if (ematch == 0) /* no matches */
- return(GRPxNM); /* return as such */
-
- if (ematch > 1) /* more than one match...ambiguous */
- if (!(fdbp->_cmffl & GRP_WILD)) /* means 2 identical group names */
- return(GRPxAMB); /* unless a wild parse */
-
- value->_pvgrp = buildgrouplist(g,ematch); /* return list of matches */
- *parselen = term-text; /* and parsed length */
- return(CMxOK); /* and return successfully */
- }
-
- /*
- * group name help routine.
- */
- PASSEDSTATIC int
- grphelp(text, textlen, fdbp, cust,lines)
- char *text;
- int textlen, cust;
- fdb *fdbp;
- int lines;
- {
- int ematch, pmatch,i,len,maxlen,cols,curcol;
- struct grp **g;
- char *term;
- int mylines = 1;
- if (!cust) { /* standard help msg */
- cmxputs("group name, one of the following:");
- }
-
- /* find matches */
- match(text, textlen, fdbp, &g, &term, &pmatch, &ematch);
- if (pmatch == 0) { /* no matches. */
- cmxnl(); /* just say so */
- cmxputs(" (No group names match current input)"); /* none here */
- return(lines-1); /* all done */
- }
-
- if (pmatch > cmcsb._cmmax) { /* too many to display */
- cmxnl();
- cmxprintf(" %d matching groups.\n",pmatch); /* just say how many. */
- return(lines-1); /* all done */
- }
-
- maxlen = 0; /* calculate number of columns */
- len = 0; /* based on maximum name length */
-
- for (i = 0 ; g[i] != NULL; i++) { /* scan through matches */
- if (g[i]->flags & GRP_PARTIAL) {
- len = strlen(g[i]->grp->gr_name); /* find longest name */
- if (maxlen < len) maxlen = len;
- }
- }
- maxlen += 3; /* put some space after the name */
- cols = (cmcsb._cmcmx+2) / maxlen; /* number of columns per line */
- if (cols <= 0) cols = 1; /* at least one column */
- curcol = 0; /* currently printing first column */
-
- for ( i = 0; g[i] != NULL; i++) { /* scan through again, and print 'em */
- if (g[i]->flags & GRP_PARTIAL) { /* found a match... */
- if (curcol == 0) {
- cmxnl(); /* new line for first column */
- if (mylines >= lines) {
- if (!cmhelp_more("--space to continue, Q to stop--"))
- return(-1);
- else {
- lines = cmcsb._cmrmx;
- mylines = 0;
- }
- }
- mylines++;
- cmxputs(" "); /* and offset a bit */
- }
- cmxputs(g[i]->grp->gr_name); /* print the name */
-
- if (curcol < cols -1) { /* if not last column */
- int j; /* space out to end of column */
- for(j = strlen(g[i]->grp->gr_name); j < maxlen; j++)
- cmxputc(SPACE);
- }
- curcol = (curcol+1) % cols; /* move to next column */
- }
- }
- cmxnl(); /* newline at the end */
- return(lines-mylines); /* all done */
- }
-
-
- /*
- * find a partial completion for a list of groups
- */
-
- PASSEDSTATIC char *
- partial(text,textlen,g,pcount,exact)
- char *text;
- int textlen;
- struct grp **g;
- int pcount;
- int *exact;
- {
- int i,j,k;
- static char buf[50];
- char tbuf[50],fbuf[50],gname[50];
- int buflen,fbuflen=0;
-
- *exact = TRUE; /* assume we find an exact match */
- strncpy(tbuf,text,textlen);
- tbuf[textlen] = '\0';
-
- buf[0] = '\0'; /* start off with no matches */
- for(i = 0, j = 0; g[i] != NULL && j < pcount; i++) {
- if (g[i]->flags & GRP_PARTIAL) {
- strcpy(fbuf,g[i]->grp->gr_name);
- fbuflen = strlen(fbuf); /* copy then name */
-
- while(!fmatch(fbuf,tbuf,FALSE)) { /* shorten until we match */
- fbuf[--fbuflen] = '\0';
- }
- strcpy(gname,g[i]->grp->gr_name);
- if (j++ == 0)
- strcpy(buf,&gname[fbuflen]); /* first time, grab completion */
- else {
- buflen = strlen(buf);
- for(k = 0; k < buflen; k++) /* otherwise trim it to match */
- if (buf[k] != gname[fbuflen+k]) {
- buf[k] = '\0'; /* if end of a name, then exact */
- if (gname[fbuflen+k] != '\0') *exact = FALSE;
- else *exact = TRUE;
- break;
- }
- }
- }
- }
- return(buf);
- }
-
- /*
- * group name completion routine
- */
- grpcomplete(text, textlen, fdbp, full, cplt, cpltlen)
- char *text,**cplt;
- int textlen,full,*cpltlen;
- fdb *fdbp;
- {
- int ematch, pmatch,i;
- struct grp **g;
- char *term;
-
- *cplt = NULL; *cpltlen = 0; /* assume no completions */
- /* find matches */
- match(text, textlen, fdbp, &g, &term, &pmatch, &ematch);
-
- if (ematch >= 1) { /* exact match? */
- *cplt = "";
- if (full) return(CMP_GO | CMP_SPC); /* just use it */
- else return(CMP_PNC);
- }
- if (pmatch == 0) { /* no match. */
- return(CMP_BEL|CMP_GO); /* just beep and wake up */
- }
- if (pmatch > 1) { /* more than one partial match. */
- int exact;
- *cplt = partial(text,textlen,g,pmatch,&exact);
- *cpltlen = strlen(*cplt);
- if (exact) return(CMP_GO|CMP_SPC);
- return(CMP_BEL); /* we could partial complete */
- } /* but for now,just beep */
- if (pmatch == 1) { /* one match */
- int exact;
- for(i = 0; g[i] != NULL; i++) {
- if (g[i]->flags & GRP_PARTIAL) { /* find it */
- /* and return the completion */
- *cplt = partial(text,textlen,g,pmatch,&exact);
- *cpltlen = strlen(*cplt);
- if (full) return(CMP_GO | CMP_SPC);
- else return(CMP_PNC);
- }
- }
- }
- return(CMP_BEL);
- }
-
- /*
- * group name matching routine.
- */
-
- static
- match(text, textlen, fdbp, who, term, pmatch, ematch)
- char *text, **term;
- int textlen, *pmatch,*ematch;
- fdb *fdbp;
- struct grp ***who;
- {
- struct grp **grps=NULL, **maybe_read_grps();
- struct grp **g,**read_grps();
- char gp[100];
- int matches=0, i,inlen;
- brktab *btab; /* break table to use */
-
- grps = maybe_read_grps(fdbp->_cmffl & GRP_UPDONLY, fdbp->_cmffl & GRP_NOUPD);
- *term = NULL;
-
- /* just update the user table */
- if (fdbp->_cmffl & GRP_UPDONLY) {
- *ematch = *pmatch = 0; /* no matches */
- return;
- }
-
- *term = NULL;
-
- if ((btab = fdbp->_cmbrk) == NULL) /* get supplied break table */
- btab = &grpbrk; /* or use default */
-
- for (inlen = 0; inlen < textlen; inlen++) { /* find # of usable chars */
- if (text[inlen] & 0x80) {
- text[inlen] &= 0x7f;
- continue;
- }
- else
- if (index("[]{}*?^,",text[inlen]))
- continue;
- else
- if ((!BREAK(btab,0x7f&text[inlen],inlen)))
- continue;
- else
- break;
- }
-
- if (inlen == textlen) /* no break char? */
- *term = NULL; /* then set no terminator */
- else
- *term = text+inlen; /* else point to it for caller */
-
- /* copy the string to match */
- for(i = 0; i < inlen; i++) gp[i] = text[i]&0x7f;
- gp[inlen] = '\0'; /* null terminated of course */
- *pmatch = *ematch = 0; /* and start with no matches */
-
- for (g = grps; *g != NULL; g++) { /* loop through all groups */
- (*g)->flags &= ~(GRP_PARTIAL | GRP_EXACT); /* assume a mismatch */
- if (fmatch((*g)->grp->gr_name,gp,TRUE)) { /* partial match? */
- (*g)->flags |= GRP_PARTIAL; /* flag */
- (*pmatch)++; /* and count it */
- if (fmatch((*g)->grp->gr_name,gp,FALSE)) { /* exact match? */
- (*g)->flags |= GRP_EXACT; /* flag and count it */
- (*ematch)++;
- }
- }
- }
- *who = grps; /* return the list */
- return;
- }
-
- /*
- * free up group list read from group file
- */
- free_grps(grps) struct grp **grps; {
- struct grp *g;
- int i;
- if (grps == NULL) return; /* no list. never mind */
- while (*grps != NULL) { /* for all groups */
- g = *grps;
- if (g->grp != NULL) { /* if there is a group entry here */
- /* free string space (note this
- is all malloc as one chunk, so
- it is all freed as one chunk */
- if (g->grp->gr_name != NULL) free(g->grp->gr_name);
- if (g->grp->gr_passwd != NULL) free(g->grp->gr_passwd);
- for (i = 0; g->grp->gr_mem[i] != NULL; i++)
- free(g->grp->gr_mem[i]);
- free(g->grp); /* free the group entry */
- grps++; /* and go to the next group */
- }
- }
- free(grps);
- }
-
-
- struct grp **
- read_grps() {
- struct grp **grps = NULL;
- int maxgrps = 0;
- int ngrps = 0;
- struct group *g,*getgrent(),*copyg();
-
- setgrent();
- while (1) {
- g = getgrent();
- if (ngrps == maxgrps) {
- grps = (struct grp **)cmrealloc(grps,
- sizeof(struct grp *)*(maxgrps+INCGRPS));
- maxgrps+=INCGRPS;
- }
- if (g == NULL) break;
- grps[ngrps] = (struct grp *)malloc(sizeof(struct grp));
- grps[ngrps]->grp = copyg(g);
- grps[ngrps++]->flags = 0;
- }
- grps[ngrps] = NULL;
- endgrent();
- return(grps);
- }
-
- grpcmp(a,b) register struct grp **a,**b; {
- return(strcmp((*a)->grp->gr_name,(*b)->grp->gr_name));
- }
-
- sort_grps(grps) struct grp **grps; {
- int i;
- for (i = 0; grps[i] != NULL; i++);
- qsort(grps,i,sizeof(struct grp *), grpcmp);
- }
-
- struct group *
- copyg(grp) struct group *grp; {
- struct group *g;
- int i;
- static int cnt = 0;
-
- g = (struct group *) malloc(sizeof (struct group)); /* get a group */
- g->gr_name = malloc(strlen(grp->gr_name)+1); /* space for the name */
- strcpy(g->gr_name,grp->gr_name); /* copy the name */
- g->gr_passwd = malloc(strlen(grp->gr_passwd)+1); /* space for the passwd */
- strcpy(g->gr_passwd,grp->gr_passwd); /* copy the passwd */
-
- for (i = 0; grp->gr_mem[i] != NULL; i++); /* count the members */
- g->gr_mem = (char **)malloc((i+1)*sizeof (char *)); /* space for ptr */
- for (i = 0; grp->gr_mem[i] != NULL; i++) { /* copy the members */
- g->gr_mem[i] = malloc(strlen(grp->gr_mem[i])+1); /* alloc space */
- strcpy(g->gr_mem[i], grp->gr_mem[i]); /* copy the name */
- }
- g->gr_mem[i] = NULL;
- g->gr_gid = grp->gr_gid;
- cnt++;
- return(g);
- }
-
-
- struct group**
- buildgrouplist(g,count) struct grp **g; {
- static struct group **gr=NULL;
- int i,j;
- if (gr != NULL) free(gr);
- gr = (struct group **)malloc((count+1)*sizeof(struct group*));
- for (i = 0,j = 0; g[i] != NULL; i++) {
- if (g[i]->flags & GRP_EXACT)
- gr[j++] = g[i]->grp;
- }
- gr[count] = NULL;
- return(gr);
- }
-
-
- struct grp **
- maybe_read_grps(always,dont)
- int always, dont;
- {
- static struct grp **grps=NULL;
- static int group_time=0;
- struct stat buf;
- int temp = always;
-
- stat("/etc/group",&buf); /* reread the group file? */
- always = group_time != 0 && always && !dont;
- dont = group_time != 0 && dont && !temp;
- if ((group_time == 0 || buf.st_mtime > group_time || always) && !dont) {
- group_time = buf.st_mtime;
- free_grps(grps); /* free up old entries */
- grps = read_grps(); /* and re read the file */
- sort_grps(grps); /* sort them */
- }
- return(grps);
- }
-
- #else /* !unix */
-
- #include "ccmd.h" /* ccmd symbols */
- #include "cmfncs.h" /* ccmd internal symbols */
-
- static brktab grpbrk = { /* all valid chars for groups */
- { /* alphanums, "~#/_-\[]," */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
- 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
- },
- {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
- 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
- }
- };
-
- int grpparse(), grphelp(), grpcomplete();
- ftspec ft_grp = { grpparse, grphelp, grpcomplete, 0, &grpbrk };
-
- PASSEDSTATIC int
- grpparse(text, textlen, fdbp, parselen, value)
- char *text;
- int textlen, *parselen;
- fdb *fdbp;
- pval *value;
- {
- int i;
- *parselen = 0;
- value->_pvgrp = NULL;
- for (i = 0; i < textlen; i++)
- if (isspace(text[textlen-1]))
- return(GRPxNM);
- return(CMxINC);
- }
-
- grpcomplete(text, textlen, fdbp, full, cplt, cpltlen)
- char *text,**cplt;
- int textlen,full,*cpltlen;
- fdb *fdbp;
- {
- *cplt = NULL;
- *cpltlen = 0;
- return(CMP_BEL|CMP_SPC|CMP_GO);
- }
-
- PASSEDSTATIC int
- grphelp(text, textlen, fdbp, cust)
- char *text;
- int textlen, cust;
- fdb *fdbp;
- {
-
- if (!cust) { /* standard help msg */
- cmxputs("group name, one of the following:");
- }
-
- cmxnl();
- cmxputs(" (No group names match current input)");
- return(CMxOK);
- }
-
- #endif /* !unix */
-
-