1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19*b30d1939SAndy Fiddaman *                                                                      *
20*b30d1939SAndy Fiddaman ***********************************************************************/
21*b30d1939SAndy Fiddaman #pragma prototyped
22*b30d1939SAndy Fiddaman /*
23*b30d1939SAndy Fiddaman  * uniq
24*b30d1939SAndy Fiddaman  *
25*b30d1939SAndy Fiddaman  * Written by David Korn
26*b30d1939SAndy Fiddaman  */
27*b30d1939SAndy Fiddaman 
28*b30d1939SAndy Fiddaman static const char usage[] =
29*b30d1939SAndy Fiddaman "[-n?\n@(#)$Id: uniq (AT&T Research) 2009-11-28 $\n]"
30*b30d1939SAndy Fiddaman USAGE_LICENSE
31*b30d1939SAndy Fiddaman "[+NAME?uniq - Report or filter out repeated lines in a file]"
32*b30d1939SAndy Fiddaman "[+DESCRIPTION?\buniq\b reads the input, compares adjacent lines, and "
33*b30d1939SAndy Fiddaman 	"writes one copy of each input line on the output.  The second "
34*b30d1939SAndy Fiddaman 	"and succeeding copies of the repeated adjacent lines are not "
35*b30d1939SAndy Fiddaman 	"written.]"
36*b30d1939SAndy Fiddaman "[+?If the output file, \aoutfile\a, is not specified, \buniq\b writes "
37*b30d1939SAndy Fiddaman 	"to standard output.  If no \ainfile\a is given, or if the \ainfile\a "
38*b30d1939SAndy Fiddaman 	"is \b-\b, \buniq\b reads from standard input with the start of "
39*b30d1939SAndy Fiddaman 	"the file defined as the current offset.]"
40*b30d1939SAndy Fiddaman "[c:count?Output the number of times each line occurred  along with "
41*b30d1939SAndy Fiddaman 	"the line.]"
42*b30d1939SAndy Fiddaman "[d:repeated|duplicates?Output the first of each duplicate line.]"
43*b30d1939SAndy Fiddaman "[D:all-repeated?Output all duplicate lines as a group with an empty "
44*b30d1939SAndy Fiddaman     "line delimiter specified by \adelimit\a:]:?[delimit:=none]"
45*b30d1939SAndy Fiddaman     "{"
46*b30d1939SAndy Fiddaman         "[n:none?Do not delimit duplicate groups.]"
47*b30d1939SAndy Fiddaman         "[p:prepend?Prepend an empty line before each group.]"
48*b30d1939SAndy Fiddaman         "[s:separate?Separate each group with an empty line.]"
49*b30d1939SAndy Fiddaman     "}"
50*b30d1939SAndy Fiddaman "[f:skip-fields]#[fields?\afields\a is the number of fields to skip over "
51*b30d1939SAndy Fiddaman     "before checking for uniqueness. A field is the minimal string matching "
52*b30d1939SAndy Fiddaman     "the BRE \b[[:blank:]]]]*[^[:blank:]]]]*\b. -\anumber\a is equivalent to "
53*b30d1939SAndy Fiddaman     "\b--skip-fields\b=\anumber\a.]"
54*b30d1939SAndy Fiddaman "[i:ignore-case?Ignore case in comparisons.]"
55*b30d1939SAndy Fiddaman "[s:skip-chars]#[chars?\achars\a is the number of characters to skip over "
56*b30d1939SAndy Fiddaman 	"before checking for uniqueness.  If specified along with \b-f\b, "
57*b30d1939SAndy Fiddaman 	"the first \achars\a after the first \afields\a are ignored.  If "
58*b30d1939SAndy Fiddaman 	"the \achars\a specifies more characters than are on the line, "
59*b30d1939SAndy Fiddaman 	"an empty string will be used for comparison. +\anumber\a is "
60*b30d1939SAndy Fiddaman 	"equivalent to \b--skip-chars\b=\anumber\a.]"
61*b30d1939SAndy Fiddaman "[u:unique?Output unique lines.]"
62*b30d1939SAndy Fiddaman "[w:check-chars]#[chars?\achars\a is the number of characters to compare "
63*b30d1939SAndy Fiddaman 	"after skipping any specified fields and characters.]"
64*b30d1939SAndy Fiddaman "\n"
65*b30d1939SAndy Fiddaman "\n[infile [outfile]]\n"
66*b30d1939SAndy Fiddaman "\n"
67*b30d1939SAndy Fiddaman "[+EXIT STATUS?]{"
68*b30d1939SAndy Fiddaman 	"[+0?The input file was successfully processed.]"
69*b30d1939SAndy Fiddaman 	"[+>0?An error occurred.]"
70*b30d1939SAndy Fiddaman "}"
71*b30d1939SAndy Fiddaman "[+SEE ALSO?\bsort\b(1), \bgrep\b(1)]"
72*b30d1939SAndy Fiddaman ;
73*b30d1939SAndy Fiddaman 
74*b30d1939SAndy Fiddaman #include <cmd.h>
75*b30d1939SAndy Fiddaman 
76*b30d1939SAndy Fiddaman #define C_FLAG	1
77*b30d1939SAndy Fiddaman #define D_FLAG	2
78*b30d1939SAndy Fiddaman #define U_FLAG	4
79*b30d1939SAndy Fiddaman 
80*b30d1939SAndy Fiddaman #define CWIDTH	4
81*b30d1939SAndy Fiddaman #define MAXCNT	9999
82*b30d1939SAndy Fiddaman 
83*b30d1939SAndy Fiddaman typedef int (*Compare_f)(const char*, const char*, size_t);
84*b30d1939SAndy Fiddaman 
uniq(Sfio_t * fdin,Sfio_t * fdout,int fields,int chars,int width,int mode,int * all,Compare_f compare)85*b30d1939SAndy Fiddaman static int uniq(Sfio_t *fdin, Sfio_t *fdout, int fields, int chars, int width, int mode, int* all, Compare_f compare)
86*b30d1939SAndy Fiddaman {
87*b30d1939SAndy Fiddaman 	register int n, f, outsize=0, mb = mbwide();
88*b30d1939SAndy Fiddaman 	register char *cp, *ep, *mp, *bufp, *outp;
89*b30d1939SAndy Fiddaman 	char *orecp, *sbufp=0, *outbuff;
90*b30d1939SAndy Fiddaman 	int reclen,oreclen= -1,count=0,cwidth=0,sep,next;
91*b30d1939SAndy Fiddaman 	if(mode&C_FLAG)
92*b30d1939SAndy Fiddaman 		cwidth = CWIDTH+1;
93*b30d1939SAndy Fiddaman 	while(1)
94*b30d1939SAndy Fiddaman 	{
95*b30d1939SAndy Fiddaman 		if(bufp = sfgetr(fdin,'\n',0))
96*b30d1939SAndy Fiddaman 			n = sfvalue(fdin);
97*b30d1939SAndy Fiddaman 		else if(bufp = sfgetr(fdin,'\n',SF_LASTR))
98*b30d1939SAndy Fiddaman 		{
99*b30d1939SAndy Fiddaman 			n = sfvalue(fdin);
100*b30d1939SAndy Fiddaman 			bufp = memcpy(fmtbuf(n + 1), bufp, n);
101*b30d1939SAndy Fiddaman 			bufp[n++] = '\n';
102*b30d1939SAndy Fiddaman 		}
103*b30d1939SAndy Fiddaman 		else
104*b30d1939SAndy Fiddaman 			n = 0;
105*b30d1939SAndy Fiddaman 		if (n)
106*b30d1939SAndy Fiddaman 		{
107*b30d1939SAndy Fiddaman 			cp = bufp;
108*b30d1939SAndy Fiddaman 			ep = cp + n;
109*b30d1939SAndy Fiddaman 			if (f = fields)
110*b30d1939SAndy Fiddaman 				while (f-->0 && cp<ep) /* skip over fields */
111*b30d1939SAndy Fiddaman 				{
112*b30d1939SAndy Fiddaman 					while (cp<ep && *cp==' ' || *cp=='\t')
113*b30d1939SAndy Fiddaman 						cp++;
114*b30d1939SAndy Fiddaman 					while (cp<ep && *cp!=' ' && *cp!='\t')
115*b30d1939SAndy Fiddaman 						cp++;
116*b30d1939SAndy Fiddaman 				}
117*b30d1939SAndy Fiddaman 			if (chars)
118*b30d1939SAndy Fiddaman 			{
119*b30d1939SAndy Fiddaman 				if (mb)
120*b30d1939SAndy Fiddaman 					for (f = chars; f; f--)
121*b30d1939SAndy Fiddaman 						mbchar(cp);
122*b30d1939SAndy Fiddaman 				else
123*b30d1939SAndy Fiddaman 					cp += chars;
124*b30d1939SAndy Fiddaman 			}
125*b30d1939SAndy Fiddaman 			if ((reclen = n - (cp - bufp)) <= 0)
126*b30d1939SAndy Fiddaman 			{
127*b30d1939SAndy Fiddaman 				reclen = 1;
128*b30d1939SAndy Fiddaman 				cp = bufp + n - 1;
129*b30d1939SAndy Fiddaman 			}
130*b30d1939SAndy Fiddaman 			else if (width >= 0 && width < reclen)
131*b30d1939SAndy Fiddaman 			{
132*b30d1939SAndy Fiddaman 				if (mb)
133*b30d1939SAndy Fiddaman 				{
134*b30d1939SAndy Fiddaman 					reclen = 0;
135*b30d1939SAndy Fiddaman 					mp = cp;
136*b30d1939SAndy Fiddaman 					while (reclen < width && mp < ep)
137*b30d1939SAndy Fiddaman 					{
138*b30d1939SAndy Fiddaman 						reclen++;
139*b30d1939SAndy Fiddaman 						mbchar(mp);
140*b30d1939SAndy Fiddaman 					}
141*b30d1939SAndy Fiddaman 					reclen = mp - cp;
142*b30d1939SAndy Fiddaman 				}
143*b30d1939SAndy Fiddaman 				else
144*b30d1939SAndy Fiddaman 					reclen = width;
145*b30d1939SAndy Fiddaman 			}
146*b30d1939SAndy Fiddaman 		}
147*b30d1939SAndy Fiddaman 		else
148*b30d1939SAndy Fiddaman 			reclen = -2;
149*b30d1939SAndy Fiddaman 		if(reclen==oreclen && (!reclen || !(*compare)(cp,orecp,reclen)))
150*b30d1939SAndy Fiddaman 		{
151*b30d1939SAndy Fiddaman 			count++;
152*b30d1939SAndy Fiddaman 			if (!all)
153*b30d1939SAndy Fiddaman 				continue;
154*b30d1939SAndy Fiddaman 			next = count;
155*b30d1939SAndy Fiddaman 		}
156*b30d1939SAndy Fiddaman 		else
157*b30d1939SAndy Fiddaman 		{
158*b30d1939SAndy Fiddaman 			next = 0;
159*b30d1939SAndy Fiddaman 			if(outsize>0)
160*b30d1939SAndy Fiddaman 			{
161*b30d1939SAndy Fiddaman 				if(((mode&D_FLAG)&&count==0) || ((mode&U_FLAG)&&count))
162*b30d1939SAndy Fiddaman 				{
163*b30d1939SAndy Fiddaman 					if(outp!=sbufp)
164*b30d1939SAndy Fiddaman 						sfwrite(fdout,outp,0);
165*b30d1939SAndy Fiddaman 				}
166*b30d1939SAndy Fiddaman 				else
167*b30d1939SAndy Fiddaman 				{
168*b30d1939SAndy Fiddaman 					if(cwidth)
169*b30d1939SAndy Fiddaman 					{
170*b30d1939SAndy Fiddaman 						if(count<9)
171*b30d1939SAndy Fiddaman 						{
172*b30d1939SAndy Fiddaman 							f = 0;
173*b30d1939SAndy Fiddaman 							while(f < CWIDTH-1)
174*b30d1939SAndy Fiddaman 								outp[f++] = ' ';
175*b30d1939SAndy Fiddaman 							outp[f++] = '0' + count + 1;
176*b30d1939SAndy Fiddaman 							outp[f] = ' ';
177*b30d1939SAndy Fiddaman 						}
178*b30d1939SAndy Fiddaman 						else if(count<MAXCNT)
179*b30d1939SAndy Fiddaman 						{
180*b30d1939SAndy Fiddaman 							count++;
181*b30d1939SAndy Fiddaman 							f = CWIDTH;
182*b30d1939SAndy Fiddaman 							outp[f--] = ' ';
183*b30d1939SAndy Fiddaman 							do
184*b30d1939SAndy Fiddaman 							{
185*b30d1939SAndy Fiddaman 								outp[f--] = '0' + (count % 10);
186*b30d1939SAndy Fiddaman 							} while (count /= 10);
187*b30d1939SAndy Fiddaman 							while (f >= 0)
188*b30d1939SAndy Fiddaman 								outp[f--] = ' ';
189*b30d1939SAndy Fiddaman 						}
190*b30d1939SAndy Fiddaman 						else
191*b30d1939SAndy Fiddaman 						{
192*b30d1939SAndy Fiddaman 							outsize -= (CWIDTH+1);
193*b30d1939SAndy Fiddaman 							if(outp!=sbufp)
194*b30d1939SAndy Fiddaman 							{
195*b30d1939SAndy Fiddaman 								if(!(sbufp=fmtbuf(outsize)))
196*b30d1939SAndy Fiddaman 									return(1);
197*b30d1939SAndy Fiddaman 								memcpy(sbufp,outp+CWIDTH+1,outsize);
198*b30d1939SAndy Fiddaman 								sfwrite(fdout,outp,0);
199*b30d1939SAndy Fiddaman 								outp = sbufp;
200*b30d1939SAndy Fiddaman 							}
201*b30d1939SAndy Fiddaman 							else
202*b30d1939SAndy Fiddaman 								outp += CWIDTH+1;
203*b30d1939SAndy Fiddaman 							sfprintf(fdout,"%4d ",count+1);
204*b30d1939SAndy Fiddaman 						}
205*b30d1939SAndy Fiddaman 					}
206*b30d1939SAndy Fiddaman 					if(sfwrite(fdout,outp,outsize) != outsize)
207*b30d1939SAndy Fiddaman 						return(1);
208*b30d1939SAndy Fiddaman 				}
209*b30d1939SAndy Fiddaman 			}
210*b30d1939SAndy Fiddaman 		}
211*b30d1939SAndy Fiddaman 		if(n==0)
212*b30d1939SAndy Fiddaman 			break;
213*b30d1939SAndy Fiddaman 		if(count = next)
214*b30d1939SAndy Fiddaman 		{
215*b30d1939SAndy Fiddaman 			if(sfwrite(fdout,outp,outsize) != outsize)
216*b30d1939SAndy Fiddaman 				return(1);
217*b30d1939SAndy Fiddaman 			if(*all >= 0)
218*b30d1939SAndy Fiddaman 				*all = 1;
219*b30d1939SAndy Fiddaman 			sep = 0;
220*b30d1939SAndy Fiddaman 		}
221*b30d1939SAndy Fiddaman 		else
222*b30d1939SAndy Fiddaman 			sep = all && *all > 0;
223*b30d1939SAndy Fiddaman 		/* save current record */
224*b30d1939SAndy Fiddaman 		if (!(outbuff = sfreserve(fdout, 0, 0)) || (outsize = sfvalue(fdout)) < 0)
225*b30d1939SAndy Fiddaman 			return(1);
226*b30d1939SAndy Fiddaman 		outp = outbuff;
227*b30d1939SAndy Fiddaman 		if(outsize < n+cwidth+sep)
228*b30d1939SAndy Fiddaman 		{
229*b30d1939SAndy Fiddaman 			/* no room in outp, clear lock and use side buffer */
230*b30d1939SAndy Fiddaman 			sfwrite(fdout,outp,0);
231*b30d1939SAndy Fiddaman 			if(!(sbufp = outp=fmtbuf(outsize=n+cwidth+sep)))
232*b30d1939SAndy Fiddaman 				return(1);
233*b30d1939SAndy Fiddaman 		}
234*b30d1939SAndy Fiddaman 		else
235*b30d1939SAndy Fiddaman 			outsize = n+cwidth+sep;
236*b30d1939SAndy Fiddaman 		memcpy(outp+cwidth+sep,bufp,n);
237*b30d1939SAndy Fiddaman 		if(sep)
238*b30d1939SAndy Fiddaman 			outp[cwidth] = '\n';
239*b30d1939SAndy Fiddaman 		oreclen = reclen;
240*b30d1939SAndy Fiddaman 		orecp = outp+cwidth+sep + (cp-bufp);
241*b30d1939SAndy Fiddaman 	}
242*b30d1939SAndy Fiddaman 	return(0);
243*b30d1939SAndy Fiddaman }
244*b30d1939SAndy Fiddaman 
245*b30d1939SAndy Fiddaman int
b_uniq(int argc,char ** argv,Shbltin_t * context)246*b30d1939SAndy Fiddaman b_uniq(int argc, char** argv, Shbltin_t* context)
247*b30d1939SAndy Fiddaman {
248*b30d1939SAndy Fiddaman 	register int mode=0;
249*b30d1939SAndy Fiddaman 	register char *cp;
250*b30d1939SAndy Fiddaman 	int fields=0, chars=0, width=-1;
251*b30d1939SAndy Fiddaman 	Sfio_t *fpin, *fpout;
252*b30d1939SAndy Fiddaman 	int* all = 0;
253*b30d1939SAndy Fiddaman 	int sep;
254*b30d1939SAndy Fiddaman 	Compare_f compare = (Compare_f)memcmp;
255*b30d1939SAndy Fiddaman 
256*b30d1939SAndy Fiddaman 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
257*b30d1939SAndy Fiddaman 	for (;;)
258*b30d1939SAndy Fiddaman 	{
259*b30d1939SAndy Fiddaman 		switch (optget(argv, usage))
260*b30d1939SAndy Fiddaman 		{
261*b30d1939SAndy Fiddaman 		case 'c':
262*b30d1939SAndy Fiddaman 			mode |= C_FLAG;
263*b30d1939SAndy Fiddaman 			continue;
264*b30d1939SAndy Fiddaman 		case 'd':
265*b30d1939SAndy Fiddaman 			mode |= D_FLAG;
266*b30d1939SAndy Fiddaman 			continue;
267*b30d1939SAndy Fiddaman 		case 'D':
268*b30d1939SAndy Fiddaman 			mode |= D_FLAG;
269*b30d1939SAndy Fiddaman 			switch ((int)opt_info.num)
270*b30d1939SAndy Fiddaman 			{
271*b30d1939SAndy Fiddaman 			case 'p':
272*b30d1939SAndy Fiddaman 				sep = 1;
273*b30d1939SAndy Fiddaman 				break;
274*b30d1939SAndy Fiddaman 			case 's':
275*b30d1939SAndy Fiddaman 				sep = 0;
276*b30d1939SAndy Fiddaman 				break;
277*b30d1939SAndy Fiddaman 			default:
278*b30d1939SAndy Fiddaman 				sep = -1;
279*b30d1939SAndy Fiddaman 				break;
280*b30d1939SAndy Fiddaman 			}
281*b30d1939SAndy Fiddaman 			all = &sep;
282*b30d1939SAndy Fiddaman 			continue;
283*b30d1939SAndy Fiddaman 		case 'i':
284*b30d1939SAndy Fiddaman 			compare = (Compare_f)strncasecmp;
285*b30d1939SAndy Fiddaman 			continue;
286*b30d1939SAndy Fiddaman 		case 'u':
287*b30d1939SAndy Fiddaman 			mode |= U_FLAG;
288*b30d1939SAndy Fiddaman 			continue;
289*b30d1939SAndy Fiddaman 		case 'f':
290*b30d1939SAndy Fiddaman 			if(*opt_info.option=='-')
291*b30d1939SAndy Fiddaman 				fields = opt_info.num;
292*b30d1939SAndy Fiddaman 			else
293*b30d1939SAndy Fiddaman 				chars = opt_info.num;
294*b30d1939SAndy Fiddaman 			continue;
295*b30d1939SAndy Fiddaman 		case 's':
296*b30d1939SAndy Fiddaman 			chars = opt_info.num;
297*b30d1939SAndy Fiddaman 			continue;
298*b30d1939SAndy Fiddaman 		case 'w':
299*b30d1939SAndy Fiddaman 			width = opt_info.num;
300*b30d1939SAndy Fiddaman 			continue;
301*b30d1939SAndy Fiddaman 		case ':':
302*b30d1939SAndy Fiddaman 			error(2, "%s", opt_info.arg);
303*b30d1939SAndy Fiddaman 			break;
304*b30d1939SAndy Fiddaman 		case '?':
305*b30d1939SAndy Fiddaman 			error(ERROR_usage(2), "%s", opt_info.arg);
306*b30d1939SAndy Fiddaman 			break;
307*b30d1939SAndy Fiddaman 		}
308*b30d1939SAndy Fiddaman 		break;
309*b30d1939SAndy Fiddaman 	}
310*b30d1939SAndy Fiddaman 	argv += opt_info.index;
311*b30d1939SAndy Fiddaman 	if(all && (mode&C_FLAG))
312*b30d1939SAndy Fiddaman 		error(2, "-c and -D are mutually exclusive");
313*b30d1939SAndy Fiddaman 	if(error_info.errors)
314*b30d1939SAndy Fiddaman 		error(ERROR_usage(2), "%s", optusage(NiL));
315*b30d1939SAndy Fiddaman 	if((cp = *argv) && (argv++,!streq(cp,"-")))
316*b30d1939SAndy Fiddaman 	{
317*b30d1939SAndy Fiddaman 		if(!(fpin = sfopen(NiL,cp,"r")))
318*b30d1939SAndy Fiddaman 			error(ERROR_system(1),"%s: cannot open",cp);
319*b30d1939SAndy Fiddaman 	}
320*b30d1939SAndy Fiddaman 	else
321*b30d1939SAndy Fiddaman 		fpin = sfstdin;
322*b30d1939SAndy Fiddaman 	if(cp = *argv)
323*b30d1939SAndy Fiddaman 	{
324*b30d1939SAndy Fiddaman 		argv++;
325*b30d1939SAndy Fiddaman 		if(!(fpout = sfopen(NiL,cp,"w")))
326*b30d1939SAndy Fiddaman 			error(ERROR_system(1),"%s: cannot create",cp);
327*b30d1939SAndy Fiddaman 	}
328*b30d1939SAndy Fiddaman 	else
329*b30d1939SAndy Fiddaman 		fpout = sfstdout;
330*b30d1939SAndy Fiddaman 	if(*argv)
331*b30d1939SAndy Fiddaman 	{
332*b30d1939SAndy Fiddaman 		error(2, "too many arguments");
333*b30d1939SAndy Fiddaman 		error(ERROR_usage(2), "%s", optusage(NiL));
334*b30d1939SAndy Fiddaman 	}
335*b30d1939SAndy Fiddaman 	error_info.errors = uniq(fpin,fpout,fields,chars,width,mode,all,compare);
336*b30d1939SAndy Fiddaman 	if(fpin!=sfstdin)
337*b30d1939SAndy Fiddaman 		sfclose(fpin);
338*b30d1939SAndy Fiddaman 	if(fpout!=sfstdout)
339*b30d1939SAndy Fiddaman 		sfclose(fpout);
340*b30d1939SAndy Fiddaman 	return(error_info.errors);
341*b30d1939SAndy Fiddaman }
342*b30d1939SAndy Fiddaman 
343