/* This program reads the public user/password file, removes the username
   and owner first and last name, and orders the result by last name.

   The program is organized as follows:
      one child process uses the ypcat utility to read the user/password file
      the main program removes the needed data from each line
      a second child process sorts
   Processes are connected by pipes, which are set up using popen  */

#include <sys/types.h>
#include <unistd.h>          
#include <stdio.h>

#define MAX_USERNAME 10  /* maximum size allocated for username */
#define MAX_NAME 20      /* maximum size of a first or last name */

int main (void)
{  FILE *fpin, *fpout;   /* file variables for main process I/O */

   char lastname [MAX_NAME];
   char ch;              /* current character being processed */
   int i;                /* index variable */

   /* print header for output */
   printf ("Table of usernames, first names, and last names on system\n\n");
   printf ("           First     Last\n");
   printf ("Username   Name      Name\n\n");
   fflush(stdout);  /* be sure headers printed before proceeding */

   /* set up child process to read user/password file */
   fpin = popen("ypcat passwd", "r");  /* connect stdout of ypcat to fpin */
   if (fpin == NULL)
     { perror ("error in starting ypcat");
       exit(1);
     }

   /* set up child process to perform the final sort */
   fpout = popen("sort -n +2", "w");  /* connect stdin of sort to fpout */
   if (fpout == NULL)
     { perror ("error in starting sort");
       exit(1);
     }

   /* use file streams fpin, fpout as I/O for name processing */
   while ((ch = fgetc(fpin)) != EOF) /* process until end of file */
     { while (ch != '\n')    /* process line */
       { /* read username -- up to first colon : */
         for (i=0; ch != ':'; i++)  /* username is line up to 1st colon */
           { fputc(ch, fpout);
             ch = fgetc(fpin);
           }
         for ( ; i < MAX_USERNAME; i++)
            fputc(' ', fpout);  /* separate username from rest by spaces */

         /* skip 3 fields, each of which end with a colon */
         while (fgetc(fpin) != ':');
         while (fgetc(fpin) != ':');
         while (fgetc(fpin) != ':');

         /* process first name -- up to space or comma*/
         ch = fgetc(fpin);
         for (i=0; (ch != ' ') && (ch != ':')&& (ch != ','); i++) 
           { fputc(ch, fpout);
             ch = fgetc(fpin);
           }
         for ( ; i < MAX_USERNAME; i++)
            fputc(' ', fpout);  /* separate username from rest by spaces */

         /* process last name -- which follows last space before colon */
         ch = fgetc(fpin);
         for (i=0; (ch != ':') && (ch != ',');) 
           { if (ch == ' ')
                i = 0;       /* start last name again if space found */
             else            /* add character to last name */
                { lastname[i] = ch;
                  i++;
                }
             ch = fgetc(fpin);
           }
         for (; i<MAX_NAME-1; i++)
           lastname[i] = ' ';  /* fill name field with spaces */
         lastname[MAX_NAME-1] = '\0';   /* terminate string with null */
         fprintf (fpout, "%s\n", lastname); /* send to stdout */

         /* read rest of line */
          while ((ch = fgetc(fpin)) != '\n');
       }
     }
   /* close the current I/O stream for main, wait for each child to finish,
      and check termination status of the child */
   if (fclose (fpin))
      { perror ("error in child running ypcat");
        exit (1);
      }
   if (pclose (fpout))
      { perror ("error in child running sort");
        exit (1);
      } 
   exit (0);
}
