1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1983, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33#include <err.h>
34#include <string.h>
35
36#include "gprof.h"
37#include "pathnames.h"
38
39int namecmp(const void *, const void *);
40int timecmp(const void *, const void *);
41
42void
43printprof(void)
44{
45    register nltype	*np;
46    nltype		**sortednlp;
47    int			idx;
48
49    actime = 0.0;
50    printf( "\f\n" );
51    flatprofheader();
52	/*
53	 *	Sort the symbol table in by time
54	 */
55    sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
56    if ( sortednlp == (nltype **) 0 )
57	errx( 1 , "[printprof] ran out of memory for time sorting" );
58    for ( idx = 0 ; idx < nname ; idx += 1 ) {
59	sortednlp[ idx ] = &nl[ idx ];
60    }
61    qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
62    for ( idx = 0 ; idx < nname ; idx += 1 ) {
63	np = sortednlp[ idx ];
64	flatprofline( np );
65    }
66    actime = 0.0;
67    free( sortednlp );
68}
69
70int
71timecmp(const void *v1, const void *v2)
72{
73    const nltype **npp1 = (const nltype **)v1;
74    const nltype **npp2 = (const nltype **)v2;
75    double	timediff;
76    long	calldiff;
77
78    timediff = (*npp2) -> time - (*npp1) -> time;
79    if ( timediff > 0.0 )
80	return 1 ;
81    if ( timediff < 0.0 )
82	return -1;
83    calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
84    if ( calldiff > 0 )
85	return 1;
86    if ( calldiff < 0 )
87	return -1;
88    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
89}
90
91    /*
92     *	header for flatprofline
93     */
94void
95flatprofheader(void)
96{
97
98    if ( bflag ) {
99	printblurb( _PATH_FLAT_BLURB );
100    }
101    printf( "\ngranularity: each sample hit covers %g byte(s)" ,
102	    scale * HISTORICAL_SCALE_2 );
103    if ( totime > 0.0 ) {
104	printf( " for %.2f%% of %.2f seconds\n\n" ,
105		100.0/totime , totime / hz );
106    } else {
107	printf( " no time accumulated\n\n" );
108	    /*
109	     *	this doesn't hurt since all the numerators will be zero.
110	     */
111	totime = 1.0;
112    }
113    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
114	    "%  " , "cumulative" , "self  " , "" , "self  " , "total " , "" );
115    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
116	    "time" , "seconds " , "seconds" , "calls" ,
117	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
118	    hz >= 10000000 ? "ns/call" : hz >= 10000 ? "us/call" : "ms/call" ,
119	    "name" );
120}
121
122void
123flatprofline(register nltype *np)
124{
125
126    if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 &&
127	 np -> childtime == 0 ) {
128	return;
129    }
130    actime += np -> time;
131    if (hz >= 10000)
132	printf( "%5.1f %10.3f %8.3f" ,
133	    100 * np -> time / totime , actime / hz , np -> time / hz );
134    else
135	printf( "%5.1f %10.2f %8.2f" ,
136	    100 * np -> time / totime , actime / hz , np -> time / hz );
137    if ( np -> ncall != 0 ) {
138	if (hz >= 10000000)
139	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
140		1e9 * np -> time / hz / np -> ncall ,
141		1e9 * ( np -> time + np -> childtime ) / hz / np -> ncall );
142	else if (hz >= 10000)
143	    printf( " %8ld %8.0f %8.0f  " , np -> ncall ,
144		1e6 * np -> time / hz / np -> ncall ,
145		1e6 * ( np -> time + np -> childtime ) / hz / np -> ncall );
146	else
147	    printf( " %8ld %8.2f %8.2f  " , np -> ncall ,
148		1000 * np -> time / hz / np -> ncall ,
149		1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
150    } else if ( np -> time != 0 || np -> childtime != 0 ) {
151	printf( " %8ld %7.2f%% %8.8s  " , np -> ncall ,
152	    100 * np -> time / ( np -> time + np -> childtime ) , "" );
153    } else {
154	printf( " %8.8s %8.8s %8.8s  " , "" , "" , "" );
155    }
156    printname( np );
157    printf( "\n" );
158}
159
160void
161gprofheader(void)
162{
163
164    if ( bflag ) {
165	printblurb( _PATH_CALLG_BLURB );
166    }
167    printf( "\ngranularity: each sample hit covers %g byte(s)" ,
168	    scale * HISTORICAL_SCALE_2 );
169    if ( printtime > 0.0 ) {
170	printf( " for %.2f%% of %.2f seconds\n\n" ,
171		100.0/printtime , printtime / hz );
172    } else {
173	printf( " no time propagated\n\n" );
174	    /*
175	     *	this doesn't hurt, since all the numerators will be 0.0
176	     */
177	printtime = 1.0;
178    }
179    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
180	"" , "" , "" , "" , "called" , "total" , "parents");
181    printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
182	"index" , "%time" , "self" , "descendents" ,
183	"called" , "self" , "name" , "index" );
184    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
185	"" , "" , "" , "" , "called" , "total" , "children");
186    printf( "\n" );
187}
188
189void
190gprofline(register nltype *np)
191{
192    char	kirkbuffer[ BUFSIZ ];
193
194    sprintf( kirkbuffer , "[%d]" , np -> index );
195    printf( "%-6.6s %5.1f %7.2f %11.2f" ,
196	    kirkbuffer ,
197	    100 * ( np -> propself + np -> propchild ) / printtime ,
198	    np -> propself / hz ,
199	    np -> propchild / hz );
200    if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
201	printf( " %7ld" , np -> npropcall );
202	if ( np -> selfcalls != 0 ) {
203	    printf( "+%-7ld " , np -> selfcalls );
204	} else {
205	    printf( " %7.7s " , "" );
206	}
207    } else {
208	printf( " %7.7s %7.7s " , "" , "" );
209    }
210    printname( np );
211    printf( "\n" );
212}
213
214void
215printgprof(nltype **timesortnlp)
216{
217    int		idx;
218    nltype	*parentp;
219
220	/*
221	 *	Print out the structured profiling list
222	 */
223    gprofheader();
224    for ( idx = 0 ; idx < nname + ncycle ; idx ++ ) {
225	parentp = timesortnlp[ idx ];
226	if ( zflag == 0 &&
227	     parentp -> ncall == 0 &&
228	     parentp -> selfcalls == 0 &&
229	     parentp -> propself == 0 &&
230	     parentp -> propchild == 0 ) {
231	    continue;
232	}
233	if ( ! parentp -> printflag ) {
234	    continue;
235	}
236	if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
237		/*
238		 *	cycle header
239		 */
240	    printcycle( parentp );
241	    printmembers( parentp );
242	} else {
243	    printparents( parentp );
244	    gprofline( parentp );
245	    printchildren( parentp );
246	}
247	printf( "\n" );
248	printf( "-----------------------------------------------\n" );
249	printf( "\n" );
250    }
251    free( timesortnlp );
252}
253
254    /*
255     *	sort by decreasing propagated time
256     *	if times are equal, but one is a cycle header,
257     *		say that's first (e.g. less, i.e. -1).
258     *	if one's name doesn't have an underscore and the other does,
259     *		say the one is first.
260     *	all else being equal, sort by names.
261     */
262int
263totalcmp(const void *v1, const void *v2)
264{
265    const nltype **npp1 = (const nltype **)v1;
266    const nltype **npp2 = (const nltype **)v2;
267    register const nltype *np1 = *npp1;
268    register const nltype *np2 = *npp2;
269    double		diff;
270
271    diff =    ( np1 -> propself + np1 -> propchild )
272	    - ( np2 -> propself + np2 -> propchild );
273    if ( diff < 0.0 )
274	    return 1;
275    if ( diff > 0.0 )
276	    return -1;
277    if ( np1 -> name == 0 && np1 -> cycleno != 0 )
278	return -1;
279    if ( np2 -> name == 0 && np2 -> cycleno != 0 )
280	return 1;
281    if ( np1 -> name == 0 )
282	return -1;
283    if ( np2 -> name == 0 )
284	return 1;
285    if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
286	return -1;
287    if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
288	return 1;
289    if ( np1 -> ncall > np2 -> ncall )
290	return -1;
291    if ( np1 -> ncall < np2 -> ncall )
292	return 1;
293    return strcmp( np1 -> name , np2 -> name );
294}
295
296void
297printparents(nltype *childp)
298{
299    nltype	*parentp;
300    arctype	*arcp;
301    nltype	*cycleheadp;
302
303    if ( childp -> cyclehead != 0 ) {
304	cycleheadp = childp -> cyclehead;
305    } else {
306	cycleheadp = childp;
307    }
308    if ( childp -> parents == 0 ) {
309	printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
310		"" , "" , "" , "" , "" , "" );
311	return;
312    }
313    sortparents( childp );
314    for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
315	parentp = arcp -> arc_parentp;
316	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
317	     ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
318		/*
319		 *	selfcall or call among siblings
320		 */
321	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
322		    "" , "" , "" , "" ,
323		    arcp -> arc_count , "" );
324	    printname( parentp );
325	    printf( "\n" );
326	} else {
327		/*
328		 *	regular parent of child
329		 */
330	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
331		    "" , "" ,
332		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
333		    arcp -> arc_count , cycleheadp -> npropcall );
334	    printname( parentp );
335	    printf( "\n" );
336	}
337    }
338}
339
340void
341printchildren(nltype *parentp)
342{
343    nltype	*childp;
344    arctype	*arcp;
345
346    sortchildren( parentp );
347    arcp = parentp -> children;
348    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
349	childp = arcp -> arc_childp;
350	if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
351	    ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
352		/*
353		 *	self call or call to sibling
354		 */
355	    printf( "%6.6s %5.5s %7.7s %11.11s %7ld %7.7s     " ,
356		    "" , "" , "" , "" , arcp -> arc_count , "" );
357	    printname( childp );
358	    printf( "\n" );
359	} else {
360		/*
361		 *	regular child of parent
362		 */
363	    printf( "%6.6s %5.5s %7.2f %11.2f %7ld/%-7ld     " ,
364		    "" , "" ,
365		    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
366		    arcp -> arc_count , childp -> cyclehead -> npropcall );
367	    printname( childp );
368	    printf( "\n" );
369	}
370    }
371}
372
373void
374printname(nltype *selfp)
375{
376
377    if ( selfp -> name != 0 ) {
378	printf( "%s" , selfp -> name );
379#	ifdef DEBUG
380	    if ( debug & DFNDEBUG ) {
381		printf( "{%d} " , selfp -> toporder );
382	    }
383	    if ( debug & PROPDEBUG ) {
384		printf( "%5.2f%% " , selfp -> propfraction );
385	    }
386#	endif /* DEBUG */
387    }
388    if ( selfp -> cycleno != 0 ) {
389	printf( " <cycle %d>" , selfp -> cycleno );
390    }
391    if ( selfp -> index != 0 ) {
392	if ( selfp -> printflag ) {
393	    printf( " [%d]" , selfp -> index );
394	} else {
395	    printf( " (%d)" , selfp -> index );
396	}
397    }
398}
399
400void
401sortchildren(nltype *parentp)
402{
403    arctype	*arcp;
404    arctype	*detachedp;
405    arctype	sorted;
406    arctype	*prevp;
407
408	/*
409	 *	unlink children from parent,
410	 *	then insertion sort back on to sorted's children.
411	 *	    *arcp	the arc you have detached and are inserting.
412	 *	    *detachedp	the rest of the arcs to be sorted.
413	 *	    sorted	arc list onto which you insertion sort.
414	 *	    *prevp	arc before the arc you are comparing.
415	 */
416    sorted.arc_childlist = 0;
417    for (  (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
418	    arcp ;
419	   (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
420	    /*
421	     *	consider *arcp as disconnected
422	     *	insert it into sorted
423	     */
424	for (   prevp = &sorted ;
425		prevp -> arc_childlist ;
426		prevp = prevp -> arc_childlist ) {
427	    if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
428		break;
429	    }
430	}
431	arcp -> arc_childlist = prevp -> arc_childlist;
432	prevp -> arc_childlist = arcp;
433    }
434	/*
435	 *	reattach sorted children to parent
436	 */
437    parentp -> children = sorted.arc_childlist;
438}
439
440void
441sortparents(nltype *childp)
442{
443    arctype	*arcp;
444    arctype	*detachedp;
445    arctype	sorted;
446    arctype	*prevp;
447
448	/*
449	 *	unlink parents from child,
450	 *	then insertion sort back on to sorted's parents.
451	 *	    *arcp	the arc you have detached and are inserting.
452	 *	    *detachedp	the rest of the arcs to be sorted.
453	 *	    sorted	arc list onto which you insertion sort.
454	 *	    *prevp	arc before the arc you are comparing.
455	 */
456    sorted.arc_parentlist = 0;
457    for (  (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
458	    arcp ;
459	   (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
460	    /*
461	     *	consider *arcp as disconnected
462	     *	insert it into sorted
463	     */
464	for (   prevp = &sorted ;
465		prevp -> arc_parentlist ;
466		prevp = prevp -> arc_parentlist ) {
467	    if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
468		break;
469	    }
470	}
471	arcp -> arc_parentlist = prevp -> arc_parentlist;
472	prevp -> arc_parentlist = arcp;
473    }
474	/*
475	 *	reattach sorted arcs to child
476	 */
477    childp -> parents = sorted.arc_parentlist;
478}
479
480    /*
481     *	print a cycle header
482     */
483void
484printcycle(nltype *cyclep)
485{
486    char	kirkbuffer[ BUFSIZ ];
487
488    sprintf( kirkbuffer , "[%d]" , cyclep -> index );
489    printf( "%-6.6s %5.1f %7.2f %11.2f %7ld" ,
490	    kirkbuffer ,
491	    100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
492	    cyclep -> propself / hz ,
493	    cyclep -> propchild / hz ,
494	    cyclep -> npropcall );
495    if ( cyclep -> selfcalls != 0 ) {
496	printf( "+%-7ld" , cyclep -> selfcalls );
497    } else {
498	printf( " %7.7s" , "" );
499    }
500    printf( " <cycle %d as a whole>\t[%d]\n" ,
501	    cyclep -> cycleno , cyclep -> index );
502}
503
504    /*
505     *	print the members of a cycle
506     */
507void
508printmembers(nltype *cyclep)
509{
510    nltype	*memberp;
511
512    sortmembers( cyclep );
513    for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
514	printf( "%6.6s %5.5s %7.2f %11.2f %7ld" ,
515		"" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
516		memberp -> npropcall );
517	if ( memberp -> selfcalls != 0 ) {
518	    printf( "+%-7ld" , memberp -> selfcalls );
519	} else {
520	    printf( " %7.7s" , "" );
521	}
522	printf( "     " );
523	printname( memberp );
524	printf( "\n" );
525    }
526}
527
528    /*
529     *	sort members of a cycle
530     */
531void
532sortmembers(nltype *cyclep)
533{
534    nltype	*todo;
535    nltype	*doing;
536    nltype	*prev;
537
538	/*
539	 *	detach cycle members from cyclehead,
540	 *	and insertion sort them back on.
541	 */
542    todo = cyclep -> cnext;
543    cyclep -> cnext = 0;
544    for (  (doing = todo)&&(todo = doing -> cnext);
545	    doing ;
546	   (doing = todo )&&(todo = doing -> cnext )){
547	for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
548	    if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
549		break;
550	    }
551	}
552	doing -> cnext = prev -> cnext;
553	prev -> cnext = doing;
554    }
555}
556
557    /*
558     *	major sort is on propself + propchild,
559     *	next is sort on ncalls + selfcalls.
560     */
561int
562membercmp(nltype *this, nltype *that)
563{
564    double	thistime = this -> propself + this -> propchild;
565    double	thattime = that -> propself + that -> propchild;
566    long	thiscalls = this -> ncall + this -> selfcalls;
567    long	thatcalls = that -> ncall + that -> selfcalls;
568
569    if ( thistime > thattime ) {
570	return GREATERTHAN;
571    }
572    if ( thistime < thattime ) {
573	return LESSTHAN;
574    }
575    if ( thiscalls > thatcalls ) {
576	return GREATERTHAN;
577    }
578    if ( thiscalls < thatcalls ) {
579	return LESSTHAN;
580    }
581    return EQUALTO;
582}
583    /*
584     *	compare two arcs to/from the same child/parent.
585     *	- if one arc is a self arc, it's least.
586     *	- if one arc is within a cycle, it's less than.
587     *	- if both arcs are within a cycle, compare arc counts.
588     *	- if neither arc is within a cycle, compare with
589     *		arc_time + arc_childtime as major key
590     *		arc count as minor key
591     */
592int
593arccmp(arctype *thisp, arctype *thatp)
594{
595    nltype	*thisparentp = thisp -> arc_parentp;
596    nltype	*thischildp = thisp -> arc_childp;
597    nltype	*thatparentp = thatp -> arc_parentp;
598    nltype	*thatchildp = thatp -> arc_childp;
599    double	thistime;
600    double	thattime;
601
602#   ifdef DEBUG
603	if ( debug & TIMEDEBUG ) {
604	    printf( "[arccmp] " );
605	    printname( thisparentp );
606	    printf( " calls " );
607	    printname ( thischildp );
608	    printf( " %f + %f %ld/%ld\n" ,
609		    thisp -> arc_time , thisp -> arc_childtime ,
610		    thisp -> arc_count , thischildp -> ncall );
611	    printf( "[arccmp] " );
612	    printname( thatparentp );
613	    printf( " calls " );
614	    printname( thatchildp );
615	    printf( " %f + %f %ld/%ld\n" ,
616		    thatp -> arc_time , thatp -> arc_childtime ,
617		    thatp -> arc_count , thatchildp -> ncall );
618	    printf( "\n" );
619	}
620#   endif /* DEBUG */
621    if ( thisparentp == thischildp ) {
622	    /* this is a self call */
623	return LESSTHAN;
624    }
625    if ( thatparentp == thatchildp ) {
626	    /* that is a self call */
627	return GREATERTHAN;
628    }
629    if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
630	thisparentp -> cycleno == thischildp -> cycleno ) {
631	    /* this is a call within a cycle */
632	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
633	    thatparentp -> cycleno == thatchildp -> cycleno ) {
634		/* that is a call within the cycle, too */
635	    if ( thisp -> arc_count < thatp -> arc_count ) {
636		return LESSTHAN;
637	    }
638	    if ( thisp -> arc_count > thatp -> arc_count ) {
639		return GREATERTHAN;
640	    }
641	    return EQUALTO;
642	} else {
643		/* that isn't a call within the cycle */
644	    return LESSTHAN;
645	}
646    } else {
647	    /* this isn't a call within a cycle */
648	if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
649	    thatparentp -> cycleno == thatchildp -> cycleno ) {
650		/* that is a call within a cycle */
651	    return GREATERTHAN;
652	} else {
653		/* neither is a call within a cycle */
654	    thistime = thisp -> arc_time + thisp -> arc_childtime;
655	    thattime = thatp -> arc_time + thatp -> arc_childtime;
656	    if ( thistime < thattime )
657		return LESSTHAN;
658	    if ( thistime > thattime )
659		return GREATERTHAN;
660	    if ( thisp -> arc_count < thatp -> arc_count )
661		return LESSTHAN;
662	    if ( thisp -> arc_count > thatp -> arc_count )
663		return GREATERTHAN;
664	    return EQUALTO;
665	}
666    }
667}
668
669void
670printblurb(const char *blurbname)
671{
672    FILE	*blurbfile;
673    int		input;
674
675    blurbfile = fopen( blurbname , "r" );
676    if ( blurbfile == NULL ) {
677	warn( "%s" , blurbname );
678	return;
679    }
680    while ( ( input = getc( blurbfile ) ) != EOF ) {
681	putchar( input );
682    }
683    fclose( blurbfile );
684}
685
686int
687namecmp(const void *v1, const void *v2)
688{
689    const nltype **npp1 = (const nltype **)v1;
690    const nltype **npp2 = (const nltype **)v2;
691
692    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
693}
694
695void
696printindex(void)
697{
698    nltype		**namesortnlp;
699    register nltype	*nlp;
700    int			idx, nnames, todo, i, j;
701    char		peterbuffer[ BUFSIZ ];
702
703	/*
704	 *	Now, sort regular function name alphabetically
705	 *	to create an index.
706	 */
707    namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
708    if ( namesortnlp == (nltype **) 0 )
709	errx( 1 , "ran out of memory for sorting");
710    for ( idx = 0 , nnames = 0 ; idx < nname ; idx++ ) {
711	if ( zflag == 0 && nl[idx].ncall == 0 && nl[idx].time == 0 )
712		continue;
713	namesortnlp[nnames++] = &nl[idx];
714    }
715    qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
716    for ( idx = 1 , todo = nnames ; idx <= ncycle ; idx++ ) {
717	namesortnlp[todo++] = &cyclenl[idx];
718    }
719    printf( "\f\nIndex by function name\n\n" );
720    idx = ( todo + 2 ) / 3;
721    for ( i = 0; i < idx ; i++ ) {
722	for ( j = i; j < todo ; j += idx ) {
723	    nlp = namesortnlp[ j ];
724	    if ( nlp -> printflag ) {
725		sprintf( peterbuffer , "[%d]" , nlp -> index );
726	    } else {
727		sprintf( peterbuffer , "(%d)" , nlp -> index );
728	    }
729	    if ( j < nnames ) {
730		printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name );
731	    } else {
732		printf( "%6.6s " , peterbuffer );
733		sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
734		printf( "%-19.19s" , peterbuffer );
735	    }
736	}
737	printf( "\n" );
738    }
739    free( namesortnlp );
740}
741