/* pcck.c:  printcap check testet die angegebene Datei oder /etc/printcap
   Version: 1.0, 8/93 M. Trapp
   Aufruf:  pcck [filename]
            Das Programm zeigt nach der Zeilennummer die fehlerhafte
	    Zeile aus der angegebenen Datei an und listet darunter
	    die entdeckten Fehler auf. Die Ausgabe erfolgt in englischer
	    Sprache, damit die Funktion perror() verwendet werden kann.
	    Wird keine Datei angegeben, so prueft pcck die Datei        
            /etc/printcap.
   Compile: cc -o pcck pcck.c
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define FALSE         0
#define TRUE          1
#define LENGTH      160         /* max. Laenge einer Zeile */
#define MAXPATHLEN 1024		/* max. Laenge eines Pfades */

void Fehler(/* char *, int, char * */);


int      AnzFehler_gi = 0;      /* Fehler in /etc/printcap */


int main (argc, argv)
int argc;
char **argv;
{
    char Zeile[LENGTH];         /* aktuelle Zeile aus /etc/printcap */
    char *h;                    /* Hilfszeiger */
    int  Laenge;                /* Zeilenlaenge */
    int  Zeilennr = 0;          /* aktuelle Zeilennummer */
    int  lp = FALSE;            /* ist ein Drucker namens 'lp' definiert?
*/
    int  Druckeranfang = TRUE;  /* Anfang einer neuen Druckerdefinition */
    FILE *pc;                   /* Dateizeiger auf /etc/printcap */
    static char Dateiname[MAXPATHLEN] = "/etc/printcap";  /* Standarddatei
*/

    if ( argc > 1 )
    {
	strcpy (Dateiname, argv[1]);
    }

    printf ("\n");   /* Leerzeile nach UNIX-prompt */
    printf ("pcck 1.0 tests %s ...\n", Dateiname);

    if ( (pc = fopen (Dateiname, "r")) == NULL )
    {
	sprintf (Zeile, "pcck-error with %s", Dateiname);
	perror (Zeile);
	exit (1);
    }  /* die Datei laesst sich nicht oeffnen */

    while ( fgets (Zeile, LENGTH, pc) != NULL )
    {
	Zeilennr++;
	if ( (*Zeile != '\n') && (*Zeile != '#') )
	{
	    if ( Druckeranfang )
	    {
		Druckeranfang = FALSE;
		if ( isspace (*Zeile) )
		{
			/* Zeile ist eingerueckt, also geht die
			   Druckerdefinition weiter, es fehlt jedoch
			   in der vorherigen Zeile das abschliessende '\'
*/
			Fehler ("the previous line doesn't end with '\\'",
			  Zeilennr, Zeile);
			h = Zeile;
			while ( isspace (*h) ) h++;
			if ( *h != ':' )
			  Fehler ("no ':' at the beginning of the line",
		    	           Zeilennr, Zeile);
		}  /* Leerzeichen am Zeilenanfang */
		if ( (strstr (Zeile, "|lp|") != NULL) || 
		     (strncmp (Zeile, "lp|", 3) == 0) )
		    if ( lp )
			Fehler ("more than one printer 'lp' defined",
			  Zeilennr, Zeile);
		    else
		      lp = TRUE;
	    }  /* neuer Drucker wird definiert */
	    else
	    {
		h = Zeile;
		if ( isspace (*h) )
		    while ( isspace (*h) ) h++;
		else
		    Fehler ("you must indent long lines",
		      Zeilennr, Zeile);
		if ( *h != ':' )
		    Fehler ("no ':' at the beginning of the line",
		      Zeilennr, Zeile);
	    }  /* kein neuer Drucker */

	    /* Zeilenende untersuchen: Doppelpunkt und ggf. \ */
	    Laenge = strlen (Zeile);  /* '\n' ist mit drin */
	    switch ( Zeile [Laenge - 2] )
	    {
		case ':':   /* Ende dieser Druckerbeschreibung: */
		    Druckeranfang = TRUE;
		    break;

		case '\\':  /* ueberlange Zeile wird fortgesetzt: */
		    if ( Zeile [Laenge - 3] != ':' )
			Fehler ("no ':' before '\\'",
			  Zeilennr, Zeile);
		    break;

		case ' ':   /* unsichtbares Leerzeichen */
		    Fehler ("line must not end with a space",
		      Zeilennr, Zeile);
		    break;

		case '\t':   /* unsichtbarer Tabulator */
		    Fehler ("line must not end with a tab-character",
		      Zeilennr, Zeile);
		    break;

		default:    /* Fehlerhaftes Zeilenende: */
		    h = malloc (80);
		    sprintf (h, "line must not end with '%c'",
Zeile[Laenge - 2]);
		    Fehler (h, Zeilennr, Zeile);
		    free (h);
		    break;

	    }  /* Fallunterscheidung Zeilenende */
	}  /* weder Leerzeile noch Kommentar */
    }  /* solange, bis das Dateiende erreicht ist */

    /* Ist Standarddrucker 'lp' definiert? */
    if ( !lp )
    {
       fprintf (stderr, "There is no printer 'lp' defined in %s!\n",
Dateiname);
       AnzFehler_gi++;
    }
    if ( AnzFehler_gi )
       fprintf (stderr, "\npcck discovered %d errors!\n\n", AnzFehler_gi);
    else
       fprintf (stderr, "%s is ok!\n\n", Dateiname);
    return (0);
}  /* main() */



void Fehler (Grund, Nummer, Zeile)
char *Grund;
int Nummer;
char *Zeile;
{
    /* Fehlerhafte Zeile bei mehreren Fehlern pro Zeile nur einmal
ausgeben */
    static int LetzteNr = 0; 

    AnzFehler_gi++;
    if ( Nummer == LetzteNr )
    {
	fprintf (stderr, "\t%s\n", Grund);
    }
    else
    {
	/* Zeile enthaelt schon Zeilenvorschub! */
	fprintf (stderr, "%d: %s", Nummer, Zeile);
	fprintf (stderr, "\t%s\n", Grund);
	LetzteNr = Nummer;
    }
}  /* Fehler() */




