1/*
2 * $Id: psa.c,v 1.5 2009-10-13 22:55:37 didg Exp $
3 *
4 * Copyright (c) 1990,1995 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
6 *
7 * PostScript Accounting, psa.
8 *
9 * psa is invoked by psf, as output for a communication program.  The
10 * communication program is expected to send a small program before and
11 * after each job, which causes the page count to be emitted in a well
12 * known format.  psa reads its input, looking for page counts and other
13 * interesting data.  Any data that it doesn't understand, it emits to
14 * stderr, the lpd log file.  Data that it does understand may be written
15 * to a status file or logged.  Once all input has been received, psa
16 * subtracts the beginning and end page counts, and log an accounting
17 * record in the accounting file.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif /* HAVE_CONFIG_H */
23
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif /* HAVE_UNISTD_H */
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31int main( int ac, char **av)
32{
33    FILE	*af;
34    char	*acc, *user, *host;
35    char	buf[ 1024 ], *p, *end;
36    int		cc, n, ipc = -1, fpc = -1;
37
38    if ( ac != 4 ) {
39	fprintf( stderr, "Usage:\t%s accounting-file user host\n", av[ 0 ] );
40	exit( 2 );
41    }
42
43    acc = av[ 1 ];
44    user = av[ 2 ];
45    host = av[ 3 ];
46
47    /*
48     * Explain n = !n ...  Is there no beauty in truth?
49     */
50    while (( cc = read( 0, buf, sizeof( buf ))) > 0 ) {
51	if ( ipc < 0 && *buf == '*' ) {
52	    /* find initial pagecount */
53	    for ( p = buf, end = buf + cc; p < end; p++ ) {
54		if ( *p == '\n' || *p == '\r' ) {
55		    break;
56		}
57	    }
58	    if ( p == end ) {
59		fprintf( stderr, "Can't find initial page count!\n" );
60		exit( 2 );
61	    }
62
63	    p++;
64	    ipc = atoi( buf + 1 );
65	    cc -= ( p - buf );
66	    if ( cc != 0 ) {
67		bcopy( p, buf, cc );
68	    }
69	} else {
70	    /* find final pagecount */
71	    for ( p = buf + cc - 1; p >= buf; p-- ) {
72		if ( *p != '\n' && *p != '\r' ) {
73		    break;
74		}
75	    }
76	    if ( p < buf ) {
77		fprintf( stderr, "Can't find final page count!\n" );
78		exit( 2 );
79	    }
80
81	    for ( ; p >= buf; p-- ) {
82		if ( *p == '\n' || *p == '\r' ) {
83		    break;
84		}
85	    }
86
87	    if ( p < buf ) {
88		p = buf;
89	    } else {
90		cc -= p - buf;
91		p++;
92	    }
93
94	    if ( *p == '*' ) {
95		n = atoi( p + 1 );
96#define max(x,y)	((x)>(y)?(x):(y))
97		fpc = max( n, fpc );
98	    }
99	}
100	if ( cc != 0 && write( 2, buf, cc ) != cc ) {
101	    fprintf( stderr, "write 1: 2 %p %d\n", buf, cc );
102	    perror( "write" );
103	    exit( 2 );
104	}
105    }
106    if ( cc < 0 ) {
107	perror( "read" );
108	exit( 2 );
109    }
110
111    if ( ipc < 0 ) {
112	fprintf( stderr, "Didn't find initial page count!\n" );
113	exit( 2 );
114    }
115
116    if ( fpc < 0 ) {
117	fprintf( stderr, "Didn't find final page count!\n" );
118	exit( 2 );
119    }
120
121    /*
122     * Write accounting record.
123     */
124    if (( af = fopen( acc, "a" )) != NULL ) {
125	fprintf( af, "%7.2f\t%s:%s\n", (float)( fpc - ipc ), host, user );
126    } else {
127	perror( acc );
128	exit( 2 );
129    }
130
131    exit( 0 );
132}
133