home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mm / mm-ccmd-0.91-20031009.tar.gz / mm-ccmd-0.91-20031009.tar / work / ccmd / cmgrp.c < prev    next >
C/C++ Source or Header  |  2002-02-20  |  13KB  |  503 lines

  1. /*
  2.  Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  the City of New York.  Permission is granted to any individual or
  4.  institution to use, copy, or redistribute this software so long as it
  5.  is not sold for profit, provided this copyright notice is retained.
  6.  
  7.  Author: Howie Kaye
  8. */
  9.  
  10. #define GRPERR
  11.  
  12. /*
  13.  * ccmd group name parser.
  14.  */
  15.  
  16. #include "ccmdlib.h"
  17.  
  18. #if CCMD_OS_UNIX
  19.  
  20. #include "cmfncs.h"
  21. #include "cmgrp.h"
  22.  
  23. #define INCGRPS 100
  24.  
  25. char *malloc(), realloc();
  26. static brktab grpbrk = {        /* all valid chars for grp */
  27.    {                    /* alphanums, "~#/_-\[]," */
  28.      0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
  29.      0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
  30.    },
  31.    {
  32.      0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x00, 0x3f,
  33.      0x80, 0x00, 0x00, 0x1e, 0x80, 0x00, 0x00, 0x1f,
  34.    },
  35. };
  36.  
  37. struct group **buildgrouplist();
  38. PASSEDSTATIC int grpparse(), grphelp(), grpcomplete();
  39. static void match(char *text, int textlen, fdb *fdbp, struct grp ***who,
  40.           char **term, int *pmatch, int *ematch);
  41.  
  42. ftspec ft_grp =  { grpparse, grphelp, grpcomplete, 0, &grpbrk };
  43.  
  44. /*
  45.  * parse routine for group names.
  46.  */
  47. PASSEDSTATIC int
  48. grpparse(text, textlen, fdbp, parselen, value)
  49. char *text;
  50. int textlen, *parselen;
  51. fdb *fdbp;
  52. pval *value;
  53. {
  54.   static struct grp **g;
  55.   char *term;
  56.   int pmatch, ematch,i;
  57.  
  58.   match(text, textlen, fdbp, &g, &term, &pmatch, &ematch); /* find matches */
  59.  
  60.   if (pmatch == 0)            /* no partial matches. */
  61.       return(GRPxNM);            /* then no matches */
  62.  
  63.   if (term == NULL)            /* unterminated....not done */
  64.     return(CMxINC);            /* return incompleteness */
  65.  
  66.   if (ematch == 0)            /* no matches */
  67.     return(GRPxNM);            /* return as such */
  68.  
  69.   if (ematch > 1)             /* more than one match...ambiguous */
  70.      if (!(fdbp->_cmffl & GRP_WILD))    /* means 2 identical group names */
  71.        return(GRPxAMB);            /* unless a wild parse */
  72.  
  73.   value->_pvgrp = buildgrouplist(g,ematch); /* return list of matches */
  74.   *parselen = term-text;        /* and parsed length */
  75.   return(CMxOK);            /* and return successfully */
  76. }
  77.  
  78. /*
  79.  * group name help routine.
  80.  */
  81. PASSEDSTATIC int
  82. grphelp(text, textlen, fdbp, cust,lines) 
  83. char *text;
  84. int textlen, cust;
  85. fdb *fdbp;
  86. int lines;
  87. {
  88.   int ematch, pmatch,i,len,maxlen,cols,curcol;
  89.   struct grp **g;
  90.   char *term;
  91.   int mylines = 1;
  92.   if (!cust) {                /* standard help msg */
  93.     cmxputs("group name, one of the following:");
  94.   }
  95.  
  96.                     /* find matches */
  97.   match(text, textlen, fdbp, &g, &term, &pmatch, &ematch);
  98.   if (pmatch == 0) {            /* no matches. */
  99.     cmxnl();                /* just say so */
  100.     cmxputs(" (No group names match current input)"); /* none here */
  101.     return(lines-1);            /* all done */
  102.   }
  103.  
  104.   if (pmatch > cmcsb._cmmax) {        /* too many to display */
  105.     cmxnl();
  106.     cmxprintf(" %d matching groups.\n",pmatch); /* just say how many. */
  107.     return(lines-1);            /* all done */
  108.   }
  109.  
  110.   maxlen = 0;                /* calculate number of columns */
  111.   len = 0;                /* based on maximum name length */
  112.  
  113.   for (i = 0 ; g[i] != NULL; i++) {    /* scan through matches */
  114.     if (g[i]->flags & GRP_PARTIAL) {
  115.       len = strlen(g[i]->grp->gr_name);    /* find longest name */
  116.       if (maxlen < len) maxlen = len;
  117.     }
  118.   }
  119.   maxlen += 3;                /* put some space after the name */
  120.   cols = (cmcsb._cmcmx+2) / maxlen;    /* number of columns per line */
  121.   if (cols <= 0) cols = 1;        /* at least one column */
  122.   curcol = 0;                /* currently printing first column */
  123.  
  124.   for ( i = 0; g[i] != NULL; i++) {    /* scan through again, and print 'em */
  125.     if (g[i]->flags & GRP_PARTIAL) {    /* found a match... */
  126.       if (curcol == 0) {
  127.     cmxnl();            /* new line for first column */
  128.     if (mylines >= lines) {
  129.       if (!cmhelp_more("--space to continue, Q to stop--"))
  130.           return(-1);
  131.       else {
  132.           lines = cmcsb._cmrmx;
  133.           mylines = 0;
  134.       }
  135.     }
  136.     mylines++;
  137.     cmxputs(" ");            /* and offset a bit */
  138.       }
  139.       cmxputs(g[i]->grp->gr_name);    /* print the name */
  140.  
  141.       if (curcol < cols -1) {        /* if not last column */
  142.     int j;                /* space out to end of column */
  143.     for(j = strlen(g[i]->grp->gr_name); j < maxlen; j++)
  144.       cmxputc(SPACE);
  145.       }
  146.       curcol = (curcol+1) % cols;        /* move to next column */
  147.     }
  148.   }
  149.   cmxnl();                /* newline at the end */
  150.   return(lines-mylines);        /* all done */
  151. }
  152.  
  153.  
  154. /*
  155.  * find a partial completion for a list of groups
  156.  */
  157.  
  158. static char *
  159. partial(text,textlen,g,pcount,exact) 
  160. char *text; 
  161. int textlen;
  162. struct grp **g;
  163. int pcount;
  164. int *exact;
  165. {
  166.   int i,j,k;
  167.   static char buf[50];
  168.   char tbuf[50],fbuf[50],gname[50];
  169.   int buflen,fbuflen=0;
  170.  
  171.   *exact = TRUE;            /* assume we find an exact match */
  172.   strncpy(tbuf,text,textlen);
  173.   tbuf[textlen] = '\0';
  174.  
  175.   buf[0] = '\0';            /* start off with no matches */
  176.   for(i = 0, j = 0; g[i] != NULL && j < pcount; i++) {
  177.     if (g[i]->flags & GRP_PARTIAL) {
  178.       strcpy(fbuf,g[i]->grp->gr_name);
  179.       fbuflen = strlen(fbuf);        /* copy then name */
  180.  
  181.       while(!fmatch(fbuf,tbuf,FALSE)) {    /* shorten until we match */
  182.     fbuf[--fbuflen] = '\0';
  183.       }
  184.       strcpy(gname,g[i]->grp->gr_name);
  185.       if (j++ == 0)
  186.     strcpy(buf,&gname[fbuflen]);    /* first time, grab completion */
  187.       else {
  188.     buflen = strlen(buf);
  189.     for(k = 0; k < buflen; k++)    /* otherwise trim it to match */
  190.       if (buf[k] != gname[fbuflen+k]) {
  191.         buf[k] = '\0';        /* if end of a name, then exact */
  192.         if (gname[fbuflen+k] != '\0') *exact = FALSE;
  193.         else *exact = TRUE;
  194.         break;
  195.       }
  196.       }
  197.     }
  198.   }
  199.   return(buf);
  200. }
  201.  
  202. /*
  203.  * group name completion routine
  204.  */
  205. PASSEDSTATIC int
  206. grpcomplete(text, textlen, fdbp, full, cplt, cpltlen)
  207. char *text,**cplt;
  208. int textlen,full,*cpltlen;
  209. fdb *fdbp;
  210. {
  211.   int ematch, pmatch,i;
  212.   struct grp **g;
  213.   char *term;
  214.  
  215.   *cplt = NULL; *cpltlen = 0;        /* assume no completions */
  216.                     /* find matches */
  217.   match(text, textlen, fdbp, &g, &term, &pmatch, &ematch);
  218.  
  219.   if (ematch >= 1) {            /* exact match? */
  220.     *cplt = "";
  221.     if (full) return(CMP_GO | CMP_SPC);    /* just use it */
  222.     else return(CMP_PNC);
  223.   }
  224.   if (pmatch == 0) {            /* no match. */
  225.     return(CMP_BEL|CMP_GO);        /* just beep and wake up */
  226.   }
  227.   if (pmatch > 1) {            /* more than one partial match. */
  228.     int exact;
  229.     *cplt = partial(text,textlen,g,pmatch,&exact);
  230.     *cpltlen = strlen(*cplt);
  231.     if (exact) return(CMP_GO|CMP_SPC);
  232.     return(CMP_BEL);            /* we could partial complete */
  233.   }                    /* but for now,just beep */
  234.   if (pmatch == 1) {            /* one match */
  235.     int exact;
  236.     for(i = 0; g[i] != NULL; i++) {
  237.       if (g[i]->flags & GRP_PARTIAL) {    /* find it */
  238.                     /* and return the completion */
  239.     *cplt = partial(text,textlen,g,pmatch,&exact);
  240.     *cpltlen = strlen(*cplt);
  241.     if (full) return(CMP_GO | CMP_SPC);
  242.     else return(CMP_PNC);
  243.       }
  244.     }
  245.   }
  246.   return(CMP_BEL);
  247. }
  248.  
  249. /*
  250.  * group name matching routine.
  251.  */
  252.  
  253. static void
  254. match(char *text, int textlen, fdb *fdbp, struct grp ***who, char **term,
  255.       int *pmatch, int *ematch)
  256. {
  257.   struct grp **grps=NULL, **maybe_read_grps();
  258.   struct grp **g,**read_grps();
  259.   char gp[100];
  260.   int matches=0, i,inlen;
  261.   brktab *btab;                /* break table to use */
  262.  
  263.   grps = maybe_read_grps(fdbp->_cmffl & GRP_UPDONLY, fdbp->_cmffl & GRP_NOUPD);
  264.   *term = NULL;
  265.   
  266.                     /* just update the user table */
  267.   if (fdbp->_cmffl & GRP_UPDONLY) {
  268.       *ematch = *pmatch = 0;        /* no matches */
  269.       return;
  270.   }
  271.  
  272.   *term = NULL;
  273.   
  274.   if ((btab = fdbp->_cmbrk) == NULL)    /* get supplied break table */
  275.     btab = &grpbrk;            /* or use default */
  276.  
  277.   for (inlen = 0; inlen < textlen; inlen++) { /* find # of usable chars */
  278.     if (text[inlen] & 0x80) {
  279.       text[inlen] &= 0x7f;
  280.       continue;
  281.     }
  282.     else
  283.       if (index("[]{}*?^,",text[inlen]))
  284.      continue;
  285.     else
  286.       if ((!BREAK(btab,0x7f&text[inlen],inlen))) 
  287.     continue;
  288.     else
  289.       break;
  290.   }
  291.  
  292.   if (inlen == textlen)            /* no break char? */
  293.     *term = NULL;            /* then set no terminator */
  294.   else
  295.     *term = text+inlen;            /* else point to it for caller */
  296.  
  297.                     /* copy the string to match */
  298.   for(i = 0; i < inlen; i++) gp[i] = text[i]&0x7f;
  299.   gp[inlen] = '\0';            /* null terminated of course */
  300.   *pmatch = *ematch = 0;        /* and start with no matches */
  301.  
  302.  for (g = grps; *g != NULL; g++) {    /* loop through all groups */
  303.     (*g)->flags &= ~(GRP_PARTIAL | GRP_EXACT); /* assume a mismatch */
  304.     if (fmatch((*g)->grp->gr_name,gp,TRUE)) { /* partial match? */
  305.       (*g)->flags |= GRP_PARTIAL;    /* flag */
  306.       (*pmatch)++;            /* and count it */
  307.       if (fmatch((*g)->grp->gr_name,gp,FALSE)) { /* exact match? */
  308.     (*g)->flags |= GRP_EXACT;    /* flag and count it */
  309.     (*ematch)++;
  310.       }
  311.     }
  312.   }
  313.   *who = grps;                /* return the list */
  314.   return;
  315. }
  316.  
  317. /*
  318.  * free up group list read from group file
  319.  */
  320. free_grps(grps) struct grp **grps; {
  321.   struct grp *g;
  322.   int i;
  323.   if (grps == NULL) return;        /* no list.  never mind */
  324.   while (*grps != NULL) {        /* for all groups */
  325.     g = *grps;
  326.     if (g->grp != NULL) {        /* if there is a group entry here */
  327.                     /* free string space (note this 
  328.                        is all malloc as one chunk, so
  329.                        it is all freed as one chunk */
  330.       if (g->grp->gr_name != NULL) free(g->grp->gr_name);
  331.       if (g->grp->gr_passwd != NULL) free(g->grp->gr_passwd);
  332.       for (i = 0; g->grp->gr_mem[i] != NULL; i++)
  333.     free(g->grp->gr_mem[i]);
  334.       free(g->grp);            /* free the group entry */
  335.       grps++;                /* and go to the next group */
  336.     }
  337.   }
  338.   free(grps);
  339. }
  340.  
  341.  
  342. struct grp **
  343. read_grps() {
  344.   struct grp **grps = NULL;
  345.   int maxgrps = 0;
  346.   int ngrps = 0;
  347.   struct group *g,*getgrent(),*copyg();
  348.   
  349.   setgrent();
  350.   while (1) {
  351.     g = getgrent();
  352.     if (ngrps == maxgrps) {
  353.       grps = (struct grp **)cmrealloc(grps,
  354.                       sizeof(struct grp *)*(maxgrps+INCGRPS));
  355.       maxgrps+=INCGRPS;
  356.     }
  357.     if (g == NULL) break;
  358.     grps[ngrps] = (struct grp *)malloc(sizeof(struct grp));
  359.     grps[ngrps]->grp = copyg(g);
  360.     grps[ngrps++]->flags = 0;
  361.   }
  362.   grps[ngrps] = NULL;
  363.   endgrent();
  364.   return(grps);
  365. }
  366.  
  367. grpcmp(a,b) register struct grp **a,**b; {
  368.   return(strcmp((*a)->grp->gr_name,(*b)->grp->gr_name));
  369. }
  370.  
  371. sort_grps(grps) struct grp **grps; {
  372.   int i;
  373.   for (i = 0; grps[i] != NULL; i++);
  374.   qsort(grps,i,sizeof(struct grp *), grpcmp);
  375. }
  376.  
  377. struct group *
  378. copyg(grp) struct group *grp; {
  379.   struct group *g;
  380.   int i;
  381.   static int cnt = 0;
  382.  
  383.   g = (struct group *) malloc(sizeof (struct group)); /* get a group */
  384.   g->gr_name = malloc(strlen(grp->gr_name)+1); /* space for the name */
  385.   strcpy(g->gr_name,grp->gr_name);    /* copy the name */
  386.   g->gr_passwd = malloc(strlen(grp->gr_passwd)+1); /* space for the passwd */
  387.   strcpy(g->gr_passwd,grp->gr_passwd);    /* copy the passwd */
  388.  
  389.   for (i = 0; grp->gr_mem[i] != NULL; i++); /* count the members */
  390.   g->gr_mem = (char **)malloc((i+1)*sizeof (char *)); /* space for ptr */
  391.   for (i = 0; grp->gr_mem[i] != NULL; i++) { /* copy the members */
  392.     g->gr_mem[i] = malloc(strlen(grp->gr_mem[i])+1); /* alloc space */
  393.     strcpy(g->gr_mem[i], grp->gr_mem[i]); /* copy the name */
  394.   }
  395.   g->gr_mem[i] = NULL;
  396.   g->gr_gid = grp->gr_gid;
  397.   cnt++;
  398.   return(g);
  399. }
  400.  
  401.  
  402. struct group**
  403. buildgrouplist(g,count) struct grp **g; {
  404.   static struct group **gr=NULL;
  405.   int i,j;
  406.   if (gr != NULL) free(gr);
  407.   gr = (struct group **)malloc((count+1)*sizeof(struct group*));
  408.   for (i = 0,j = 0; g[i] != NULL; i++) {
  409.     if (g[i]->flags & GRP_EXACT)
  410.       gr[j++] = g[i]->grp;
  411.   }
  412.   gr[count] = NULL;
  413.   return(gr);
  414. }
  415.  
  416.  
  417. struct grp **
  418. maybe_read_grps(always,dont)
  419. int always, dont;
  420. {
  421.     static struct grp **grps=NULL;
  422.     static int group_time=0;
  423.     struct stat buf;
  424.     int temp = always;
  425.  
  426.     stat("/etc/group",&buf);        /* reread the group file? */
  427.     always = group_time != 0 && always && !dont;
  428.     dont = group_time != 0 && dont && !temp;
  429.     if ((group_time == 0 || buf.st_mtime > group_time || always) && !dont) {
  430.     group_time = buf.st_mtime;
  431.     free_grps(grps);        /* free up old entries */
  432.     grps = read_grps();        /* and re read the file */
  433.     sort_grps(grps);        /* sort them */
  434.     }
  435.     return(grps);
  436. }
  437.  
  438. #else /* !CCMD_OS_UNIX */
  439.  
  440. #include "ccmd.h"            /* ccmd symbols */
  441. #include "cmfncs.h"            /* ccmd internal symbols */
  442.  
  443. static brktab grpbrk = {        /* all valid chars for groups */
  444.   {                    /* alphanums, "~#/_-\[]," */
  445.     0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
  446.     0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
  447.   },
  448.   {
  449.     0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 0x00, 0x3f,
  450.     0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x0b,
  451.   }
  452. };
  453.  
  454. PASSEDSTATIC int grpparse(), grphelp(), grpcomplete();
  455.  
  456. ftspec ft_grp =  { grpparse, grphelp, grpcomplete, 0, &grpbrk };
  457.  
  458. PASSEDSTATIC int
  459. grpparse(text, textlen, fdbp, parselen, value)
  460. char *text;
  461. int textlen, *parselen;
  462. fdb *fdbp;
  463. pval *value;
  464. {
  465.   int i;
  466.   *parselen = 0;
  467.   value->_pvgrp = NULL;
  468.   for (i = 0; i < textlen; i++) 
  469.     if (isspace(text[textlen-1])) 
  470.       return(GRPxNM);
  471.   return(CMxINC);
  472. }
  473.  
  474. PASSEDSTATIC int
  475. grpcomplete(text, textlen, fdbp, full, cplt, cpltlen)
  476. char *text,**cplt;
  477. int textlen,full,*cpltlen;
  478. fdb *fdbp;
  479. {
  480.   *cplt = NULL; 
  481.   *cpltlen = 0;
  482.   return(CMP_BEL|CMP_SPC|CMP_GO);
  483. }
  484.  
  485. PASSEDSTATIC int
  486. grphelp(text, textlen, fdbp, cust) 
  487. char *text;
  488. int textlen, cust;
  489. fdb *fdbp;
  490. {
  491.  
  492.   if (!cust) {                /* standard help msg */
  493.     cmxputs("group name, one of the following:");
  494.   }
  495.  
  496.   cmxnl();
  497.   cmxputs(" (No group names match current input)");
  498.   return(CMxOK);
  499. }
  500.  
  501. #endif /* !CCMD_OS_UNIX */
  502.  
  503.