~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to dbug/dbug_analyze.c

  • Committer: Brian Aker
  • Date: 2008-07-18 20:10:26 UTC
  • mfrom: (51.3.29 remove-dbug)
  • Revision ID: brian@tangent.org-20080718201026-tto5golt0xhwqe4a
Merging in Jay's final patch on dbug.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Analyze the profile file (cmon.out) written out by the dbug
3
 
 * routines with profiling enabled.
4
 
 *
5
 
 * Copyright June 1987, Binayak Banerjee
6
 
 * All rights reserved.
7
 
 *
8
 
 * This program may be freely distributed under the same terms and
9
 
 * conditions as Fred Fish's Dbug package.
10
 
 *
11
 
 * Compile with -- cc -O -s -o %s analyze.c
12
 
 *
13
 
 * Analyze will read an trace file created by the dbug package
14
 
 * (when run with traceing enabled).  It will then produce a
15
 
 * summary on standard output listing the name of each traced
16
 
 * function, the number of times it was called, the percentage
17
 
 * of total calls, the time spent executing the function, the
18
 
 * proportion of the total time and the 'importance'.  The last
19
 
 * is a metric which is obtained by multiplying the proportions
20
 
 * of calls and the proportions of time for each function.  The
21
 
 * greater the importance, the more likely it is that a speedup
22
 
 * could be obtained by reducing the time taken by that function.
23
 
 *
24
 
 * Note that the timing values that you obtain are only rough
25
 
 * measures.  The overhead of the dbug package is included
26
 
 * within.  However, there is no need to link in special profiled
27
 
 * libraries and the like.
28
 
 *
29
 
 * CHANGES:
30
 
 *
31
 
 *      2-Mar-89: fnf
32
 
 *      Changes to support tracking of stack usage.  This required
33
 
 *      reordering the fields in the profile log file to make
34
 
 *      parsing of different record types easier.  Corresponding
35
 
 *      changes made in dbug runtime library.  Also used this
36
 
 *      opportunity to reformat the code more to my liking (my
37
 
 *      apologies to Binayak Banerjee for "uglifying" his code).
38
 
 *
39
 
 *      24-Jul-87: fnf
40
 
 *      Because I tend to use functions names like
41
 
 *      "ExternalFunctionDoingSomething", I've rearranged the
42
 
 *      printout to put the function name last in each line, so
43
 
 *      long names don't screw up the formatting unless they are
44
 
 *      *very* long and wrap around the screen width...
45
 
 *
46
 
 *      24-Jul-87: fnf
47
 
 *      Modified to put out table very similar to Unix profiler
48
 
 *      by default, but also puts out original verbose table
49
 
 *      if invoked with -v flag.
50
 
 */
51
 
 
52
 
#include <my_global.h>
53
 
#include <m_string.h>
54
 
#include <my_pthread.h>
55
 
 
56
 
static char *my_name;
57
 
static int verbose;
58
 
 
59
 
/*
60
 
 * Structure of the stack.
61
 
 */
62
 
 
63
 
#define PRO_FILE        "dbugmon.out"   /* Default output file name */
64
 
#define STACKSIZ        100             /* Maximum function nesting */
65
 
#define MAXPROCS        10000           /* Maximum number of function calls */
66
 
 
67
 
# ifdef BSD
68
 
#       include <sysexits.h>
69
 
# else
70
 
#       define EX_SOFTWARE 1
71
 
#       define EX_DATAERR 1
72
 
#       define EX_USAGE 1
73
 
#       define EX_OSERR 1
74
 
#       define EX_IOERR 1
75
 
#ifndef EX_OK
76
 
#       define EX_OK 0
77
 
#endif
78
 
# endif
79
 
 
80
 
#define __MERF_OO_ "%s: Malloc Failed in %s: %d\n"
81
 
 
82
 
#define MALLOC(Ptr,Num,Typ) do  /* Malloc w/error checking & exit */ \
83
 
        if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
84
 
                {fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
85
 
                exit(EX_OSERR);} while(0)
86
 
 
87
 
#define Malloc(Ptr,Num,Typ) do  /* Weaker version of above */\
88
 
        if (!(Ptr = (Typ *)malloc((Num)*(sizeof(Typ))))) \
89
 
                fprintf(stderr,__MERF_OO_,my_name,__FILE__,__LINE__);\
90
 
                 while(0)
91
 
 
92
 
#define FILEOPEN(Fp,Fn,Mod) do  /* File open with error exit */ \
93
 
        if (!(Fp = fopen(Fn,Mod)))\
94
 
                {fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
95
 
                exit(EX_IOERR);} while(0)
96
 
 
97
 
#define Fileopen(Fp,Fn,Mod) do  /* Weaker version of above */ \
98
 
        if(!(Fp = fopen(Fn,Mod))) \
99
 
                fprintf(stderr,"%s: Couldn't open %s\n",my_name,Fn);\
100
 
        while(0)
101
 
 
102
 
 
103
 
struct stack_t {
104
 
    unsigned int pos;                   /* which function? */
105
 
    unsigned long time;                 /* Time that this was entered */
106
 
    unsigned long children;             /* Time spent in called funcs */
107
 
};
108
 
 
109
 
static struct stack_t fn_stack[STACKSIZ+1];
110
 
 
111
 
static unsigned int stacktop = 0;       /* Lowest stack position is a dummy */
112
 
 
113
 
static unsigned long tot_time = 0;
114
 
static unsigned long tot_calls = 0;
115
 
static unsigned long highstack = 0;
116
 
static unsigned long lowstack = (ulong) ~0;
117
 
 
118
 
/*
119
 
 * top() returns a pointer to the top item on the stack.
120
 
 * (was a function, now a macro)
121
 
 */
122
 
 
123
 
#define top()   &fn_stack[stacktop]
124
 
 
125
 
/*
126
 
 * Push - Push the given record on the stack.
127
 
 */
128
 
 
129
 
void push (name_pos, time_entered)
130
 
register unsigned int name_pos;
131
 
register unsigned long time_entered;
132
 
{
133
 
    register struct stack_t *t;
134
 
 
135
 
    DBUG_ENTER("push");
136
 
    if (++stacktop > STACKSIZ) {
137
 
        fprintf (DBUG_FILE,"%s: stack overflow (%s:%d)\n",
138
 
                my_name, __FILE__, __LINE__);
139
 
        exit (EX_SOFTWARE);
140
 
    }
141
 
    DBUG_PRINT ("push", ("%d %ld",name_pos,time_entered));
142
 
    t = &fn_stack[stacktop];
143
 
    t -> pos = name_pos;
144
 
    t -> time = time_entered;
145
 
    t -> children = 0;
146
 
    DBUG_VOID_RETURN;
147
 
}
148
 
 
149
 
/*
150
 
 * Pop - pop the top item off the stack, assigning the field values
151
 
 * to the arguments. Returns 0 on stack underflow, or on popping first
152
 
 * item off stack.
153
 
 */
154
 
 
155
 
unsigned int pop (name_pos, time_entered, child_time)
156
 
register unsigned int *name_pos;
157
 
register unsigned long *time_entered;
158
 
register unsigned long *child_time;
159
 
{
160
 
    register struct stack_t *temp;
161
 
    register unsigned int rtnval;
162
 
 
163
 
    DBUG_ENTER ("pop");
164
 
 
165
 
    if (stacktop < 1) {
166
 
        rtnval = 0;
167
 
    } else {
168
 
        temp =  &fn_stack[stacktop];
169
 
        *name_pos = temp->pos;
170
 
        *time_entered = temp->time;
171
 
        *child_time = temp->children;
172
 
        DBUG_PRINT ("pop", ("%d %lu %lu",*name_pos,*time_entered,*child_time));
173
 
        rtnval = stacktop--;
174
 
    }
175
 
    DBUG_RETURN (rtnval);
176
 
}
177
 
 
178
 
/*
179
 
 * We keep the function info in another array (serves as a simple
180
 
 * symbol table)
181
 
 */
182
 
 
183
 
struct module_t {
184
 
    char *name;
185
 
    unsigned long m_time;
186
 
    unsigned long m_calls;
187
 
    unsigned long m_stkuse;
188
 
};
189
 
 
190
 
static struct module_t modules[MAXPROCS];
191
 
 
192
 
/*
193
 
 * We keep a binary search tree in order to look up function names
194
 
 * quickly (and sort them at the end.
195
 
 */
196
 
 
197
 
struct bnode {
198
 
    unsigned int lchild;        /* Index of left subtree */
199
 
    unsigned int rchild;        /* Index of right subtree */
200
 
    unsigned int pos;           /* Index of module_name entry */
201
 
};
202
 
 
203
 
static struct bnode s_table[MAXPROCS];
204
 
 
205
 
static unsigned int n_items = 0;        /* No. of items in the array so far */
206
 
 
207
 
/*
208
 
 * Need a function to allocate space for a string and squirrel it away.
209
 
 */
210
 
 
211
 
char *strsave (s)
212
 
char *s;
213
 
{
214
 
    register char *retval;
215
 
    register unsigned int len;
216
 
 
217
 
    DBUG_ENTER ("strsave");
218
 
    DBUG_PRINT ("strsave", ("%s",s));
219
 
    if (!s || (len = strlen (s)) == 0) {
220
 
        DBUG_RETURN (0);
221
 
    }
222
 
    MALLOC (retval, ++len, char);
223
 
    strcpy (retval, s);
224
 
    DBUG_RETURN (retval);
225
 
}
226
 
 
227
 
/*
228
 
 * add() - adds m_name to the table (if not already there), and returns
229
 
 * the index of its location in the table.  Checks s_table (which is a
230
 
 * binary search tree) to see whether or not it should be added.
231
 
 */
232
 
 
233
 
unsigned int add (m_name)
234
 
char *m_name;
235
 
{
236
 
    register unsigned int ind = 0;
237
 
    register int cmp;
238
 
 
239
 
    DBUG_ENTER ("add");
240
 
    if (n_items == 0) {         /* First item to be added */
241
 
        s_table[0].pos = ind;
242
 
        s_table[0].lchild = s_table[0].rchild = MAXPROCS;
243
 
        addit:
244
 
        modules[n_items].name = strsave (m_name);
245
 
        modules[n_items].m_time = 0;
246
 
        modules[n_items].m_calls = 0;
247
 
        modules[n_items].m_stkuse = 0;
248
 
        DBUG_RETURN (n_items++);
249
 
    }
250
 
    while ((cmp = strcmp (m_name,modules[ind].name))) {
251
 
        if (cmp < 0) {  /* In left subtree */
252
 
            if (s_table[ind].lchild == MAXPROCS) {
253
 
                /* Add as left child */
254
 
                if (n_items >= MAXPROCS) {
255
 
                    fprintf (DBUG_FILE,
256
 
                            "%s: Too many functions being profiled\n",
257
 
                             my_name);
258
 
                    exit (EX_SOFTWARE);
259
 
                }
260
 
                s_table[n_items].pos = s_table[ind].lchild = n_items;
261
 
                s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
262
 
#ifdef notdef
263
 
                modules[n_items].name = strsave (m_name);
264
 
                modules[n_items].m_time = modules[n_items].m_calls = 0;
265
 
                DBUG_RETURN (n_items++);
266
 
#else
267
 
                goto addit;
268
 
#endif
269
 
 
270
 
            }
271
 
            ind = s_table[ind].lchild; /* else traverse l-tree */
272
 
        } else {
273
 
            if (s_table[ind].rchild == MAXPROCS) {
274
 
                /* Add as right child */
275
 
                if (n_items >= MAXPROCS) {
276
 
                    fprintf (DBUG_FILE,
277
 
                             "%s: Too many functions being profiled\n",
278
 
                             my_name);
279
 
                    exit (EX_SOFTWARE);
280
 
                }
281
 
                s_table[n_items].pos = s_table[ind].rchild = n_items;
282
 
                s_table[n_items].lchild = s_table[n_items].rchild = MAXPROCS;
283
 
#ifdef notdef
284
 
                modules[n_items].name = strsave (m_name);
285
 
                modules[n_items].m_time = modules[n_items].m_calls = 0;
286
 
                DBUG_RETURN (n_items++);
287
 
#else
288
 
                goto addit;
289
 
#endif
290
 
 
291
 
            }
292
 
            ind = s_table[ind].rchild; /* else traverse r-tree */
293
 
        }
294
 
    }
295
 
    DBUG_RETURN (ind);
296
 
}
297
 
 
298
 
/*
299
 
 * process() - process the input file, filling in the modules table.
300
 
 */
301
 
 
302
 
void process (inf)
303
 
FILE *inf;
304
 
{
305
 
  char buf[BUFSIZ];
306
 
  char fn_name[64];             /* Max length of fn_name */
307
 
  unsigned long fn_time;
308
 
  unsigned long fn_sbot;
309
 
  unsigned long fn_ssz;
310
 
  unsigned long lastuse;
311
 
  unsigned int pos;
312
 
  unsigned long local_time;
313
 
  unsigned int oldpos;
314
 
  unsigned long oldtime;
315
 
  unsigned long oldchild;
316
 
  struct stack_t *t;
317
 
 
318
 
  DBUG_ENTER ("process");
319
 
  while (fgets (buf,BUFSIZ,inf) != NULL) {
320
 
    switch (buf[0]) {
321
 
    case 'E':
322
 
      sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
323
 
      DBUG_PRINT ("erec", ("%ld %s", fn_time, fn_name));
324
 
      pos = add (fn_name);
325
 
      push (pos, fn_time);
326
 
      break;
327
 
    case 'X':
328
 
      sscanf (buf+2, "%ld %64s", &fn_time, fn_name);
329
 
      DBUG_PRINT ("xrec", ("%ld %s", fn_time, fn_name));
330
 
      pos = add (fn_name);
331
 
      /*
332
 
       * An exited function implies that all stacked
333
 
       * functions are also exited, until the matching
334
 
       * function is found on the stack.
335
 
       */
336
 
      while (pop (&oldpos, &oldtime, &oldchild)) {
337
 
        DBUG_PRINT ("popped", ("%lu %lu", oldtime, oldchild));
338
 
        local_time = fn_time - oldtime;
339
 
        t = top ();
340
 
        t -> children += local_time;
341
 
        DBUG_PRINT ("update", ("%s", modules[t -> pos].name));
342
 
        DBUG_PRINT ("update", ("%lu", t -> children));
343
 
        local_time -= oldchild;
344
 
        modules[oldpos].m_time += local_time;
345
 
        modules[oldpos].m_calls++;
346
 
        tot_time += local_time;
347
 
        tot_calls++;
348
 
        if (pos == oldpos) {
349
 
          goto next_line;       /* Should be a break2 */
350
 
        }
351
 
      }
352
 
      /*
353
 
       * Assume that item seen started at time 0.
354
 
       * (True for function main).  But initialize
355
 
       * it so that it works the next time too.
356
 
       */
357
 
      t = top ();
358
 
      local_time = fn_time - t -> time - t -> children;
359
 
      t -> time = fn_time; t -> children = 0;
360
 
      modules[pos].m_time += local_time;
361
 
      modules[pos].m_calls++;
362
 
      tot_time += local_time;
363
 
      tot_calls++;
364
 
      break;
365
 
    case 'S':
366
 
      sscanf (buf+2, "%lx %lx %64s", &fn_sbot, &fn_ssz, fn_name);
367
 
      DBUG_PRINT ("srec", ("%lx %lx %s", fn_sbot, fn_ssz, fn_name));
368
 
      pos = add (fn_name);
369
 
      lastuse = modules[pos].m_stkuse;
370
 
#if 0
371
 
      /*
372
 
       *  Needs further thought.  Stack use is determined by
373
 
       *  difference in stack between two functions with DBUG_ENTER
374
 
       *  macros.  If A calls B calls C, where A and C have the
375
 
       *  macros, and B doesn't, then B's stack use will be lumped
376
 
       *  in with either A's or C's.  If somewhere else A calls
377
 
       *  C directly, the stack use will seem to change.  Just
378
 
       *  take the biggest for now...
379
 
       */
380
 
      if (lastuse > 0 && lastuse != fn_ssz) {
381
 
        fprintf (stderr,
382
 
                 "warning - %s stack use changed (%lx to %lx)\n",
383
 
                 fn_name, lastuse, fn_ssz);
384
 
      }
385
 
#endif
386
 
      if (fn_ssz > lastuse) {
387
 
        modules[pos].m_stkuse = fn_ssz;
388
 
      }
389
 
      if (fn_sbot > highstack) {
390
 
        highstack = fn_sbot;
391
 
      } else if (fn_sbot < lowstack) {
392
 
        lowstack = fn_sbot;
393
 
      }
394
 
      break;
395
 
    default:
396
 
      fprintf (stderr, "unknown record type '%c'\n", buf[0]);
397
 
      break;
398
 
    }
399
 
  next_line:;
400
 
  }
401
 
 
402
 
  /*
403
 
   * Now, we've hit eof.  If we still have stuff stacked, then we
404
 
   * assume that the user called exit, so give everything the exited
405
 
   * time of fn_time.
406
 
   */
407
 
  while (pop (&oldpos,&oldtime,&oldchild)) {
408
 
    local_time = fn_time - oldtime;
409
 
    t = top ();
410
 
    t -> children += local_time;
411
 
    local_time -= oldchild;
412
 
    modules[oldpos].m_time += local_time;
413
 
    modules[oldpos].m_calls++;
414
 
    tot_time += local_time;
415
 
    tot_calls++;
416
 
  }
417
 
  DBUG_VOID_RETURN;
418
 
}
419
 
 
420
 
/*
421
 
 * out_header () -- print out the header of the report.
422
 
 */
423
 
 
424
 
void out_header (outf)
425
 
FILE *outf;
426
 
{
427
 
    DBUG_ENTER ("out_header");
428
 
    if (verbose) {
429
 
        fprintf (outf, "Profile of Execution\n");
430
 
        fprintf (outf, "Execution times are in milliseconds\n\n");
431
 
        fprintf (outf, "    Calls\t\t\t    Time\n");
432
 
        fprintf (outf, "    -----\t\t\t    ----\n");
433
 
        fprintf (outf, "Times\tPercentage\tTime Spent\tPercentage\n");
434
 
        fprintf (outf, "Called\tof total\tin Function\tof total    Importance\tFunction\n");
435
 
        fprintf (outf, "======\t==========\t===========\t==========  ==========\t========\t\n");
436
 
    } else {
437
 
        fprintf (outf, "%ld bytes of stack used, from %lx down to %lx\n\n",
438
 
                 highstack - lowstack, highstack, lowstack);
439
 
        fprintf (outf,
440
 
                 "   %%time     sec   #call ms/call  %%calls  weight   stack  name\n");
441
 
    }
442
 
    DBUG_VOID_RETURN;
443
 
}
444
 
 
445
 
/*
446
 
 * out_trailer () - writes out the summary line of the report.
447
 
 */
448
 
 
449
 
void out_trailer (outf,sum_calls,sum_time)
450
 
FILE *outf;
451
 
unsigned long int sum_calls, sum_time;
452
 
{
453
 
    DBUG_ENTER ("out_trailer");
454
 
    if (verbose)
455
 
    {
456
 
      fprintf(outf, "======\t==========\t===========\t==========\t========\n");
457
 
      fprintf(outf, "%6ld\t%10.2f\t%11ld\t%10.2f\t\t%-15s\n",
458
 
              sum_calls, 100.0, sum_time, 100.0, "Totals");
459
 
    }
460
 
    DBUG_VOID_RETURN;
461
 
}
462
 
 
463
 
/*
464
 
 * out_item () - prints out the output line for a single entry,
465
 
 * and sets the calls and time fields appropriately.
466
 
 */
467
 
 
468
 
void out_item (outf, m,called,timed)
469
 
FILE *outf;
470
 
register struct module_t *m;
471
 
unsigned long int *called, *timed;
472
 
{
473
 
    char *name = m -> name;
474
 
    register unsigned int calls = m -> m_calls;
475
 
    register unsigned long local_time = m -> m_time;
476
 
    register unsigned long stkuse = m -> m_stkuse;
477
 
    unsigned int import;
478
 
    double per_time = 0.0;
479
 
    double per_calls = 0.0;
480
 
    double ms_per_call, local_ftime;
481
 
 
482
 
    DBUG_ENTER ("out_item");
483
 
 
484
 
    if (tot_time > 0) {
485
 
        per_time = (double) (local_time * 100) / (double) tot_time;
486
 
    }
487
 
    if (tot_calls > 0) {
488
 
        per_calls = (double) (calls * 100) / (double) tot_calls;
489
 
    }
490
 
    import = (unsigned int) (per_time * per_calls);
491
 
 
492
 
    if (verbose) {
493
 
        fprintf (outf, "%6d\t%10.2f\t%11ld\t%10.2f  %10d\t%-15s\n",
494
 
                calls, per_calls, local_time, per_time, import, name);
495
 
    } else {
496
 
        ms_per_call = local_time;
497
 
        ms_per_call /= calls;
498
 
        local_ftime = local_time;
499
 
        local_ftime /= 1000;
500
 
        fprintf(outf, "%8.2f%8.3f%8u%8.3f%8.2f%8u%8lu  %-s\n",
501
 
                per_time, local_ftime, calls, ms_per_call, per_calls, import,
502
 
                stkuse, name);
503
 
    }
504
 
    *called = calls;
505
 
    *timed = local_time;
506
 
    DBUG_VOID_RETURN;
507
 
}
508
 
 
509
 
/*
510
 
 * out_body (outf, root,s_calls,s_time) -- Performs an inorder traversal
511
 
 * on the binary search tree (root).  Calls out_item to actually print
512
 
 * the item out.
513
 
 */
514
 
 
515
 
void out_body (outf, root,s_calls,s_time)
516
 
FILE *outf;
517
 
register unsigned int root;
518
 
register unsigned long int *s_calls, *s_time;
519
 
{
520
 
    unsigned long int calls, local_time;
521
 
 
522
 
    DBUG_ENTER ("out_body");
523
 
    DBUG_PRINT ("out_body", ("%lu,%lu",*s_calls,*s_time));
524
 
    if (root == MAXPROCS) {
525
 
        DBUG_PRINT ("out_body", ("%lu,%lu",*s_calls,*s_time));
526
 
    } else {
527
 
        while (root != MAXPROCS) {
528
 
            out_body (outf, s_table[root].lchild,s_calls,s_time);
529
 
            out_item (outf, &modules[s_table[root].pos],&calls,&local_time);
530
 
            DBUG_PRINT ("out_body", ("-- %lu -- %lu --", calls, local_time));
531
 
            *s_calls += calls;
532
 
            *s_time += local_time;
533
 
            root = s_table[root].rchild;
534
 
        }
535
 
        DBUG_PRINT ("out_body", ("%lu,%lu", *s_calls, *s_time));
536
 
    }
537
 
    DBUG_VOID_RETURN;
538
 
}
539
 
 
540
 
/*
541
 
 * output () - print out a nice sorted output report on outf.
542
 
 */
543
 
 
544
 
void output (outf)
545
 
FILE *outf;
546
 
{
547
 
    unsigned long int sum_calls = 0;
548
 
    unsigned long int sum_time = 0;
549
 
 
550
 
    DBUG_ENTER ("output");
551
 
    if (n_items == 0) {
552
 
        fprintf (outf, "%s: No functions to trace\n", my_name);
553
 
        exit (EX_DATAERR);
554
 
    }
555
 
    out_header (outf);
556
 
    out_body (outf, 0,&sum_calls,&sum_time);
557
 
    out_trailer (outf, sum_calls,sum_time);
558
 
    DBUG_VOID_RETURN;
559
 
}
560
 
 
561
 
 
562
 
#define usage() fprintf (DBUG_FILE,"Usage: %s [-v] [prof-file]\n",my_name)
563
 
 
564
 
#ifdef MSDOS
565
 
extern int getopt(int argc, char **argv, char *opts);
566
 
#endif
567
 
extern int optind;
568
 
extern char *optarg;
569
 
 
570
 
int main (int argc, char **argv)
571
 
{
572
 
    register int c;
573
 
    int badflg = 0;
574
 
    FILE *infile;
575
 
    FILE *outfile = {stdout};
576
 
 
577
 
#ifdef THREAD
578
 
#if defined(HAVE_PTHREAD_INIT)
579
 
  pthread_init();                       /* Must be called before DBUG_ENTER */
580
 
#endif
581
 
  my_thread_global_init();
582
 
#endif /* THREAD */
583
 
  {
584
 
    DBUG_ENTER ("main");
585
 
    DBUG_PROCESS (argv[0]);
586
 
    my_name = argv[0];
587
 
    while ((c = getopt (argc,argv,"#:v")) != EOF) {
588
 
        switch (c) {
589
 
            case '#': /* Debugging Macro enable */
590
 
                DBUG_PUSH (optarg);
591
 
                break;
592
 
            case 'v': /* Verbose mode */
593
 
                verbose++;
594
 
                break;
595
 
            default:
596
 
                badflg++;
597
 
                break;
598
 
        }
599
 
    }
600
 
    if (badflg) {
601
 
        usage ();
602
 
        DBUG_RETURN (EX_USAGE);
603
 
    }
604
 
    if (optind < argc) {
605
 
        FILEOPEN (infile, argv[optind], "r");
606
 
    } else {
607
 
        FILEOPEN (infile, PRO_FILE, "r");
608
 
    }
609
 
    process (infile);
610
 
    output (outfile);
611
 
    DBUG_RETURN (EX_OK);
612
 
}
613
 
}
614
 
 
615
 
#ifdef MSDOS
616
 
 
617
 
/*
618
 
 * From std-unix@ut-sally.UUCP (Moderator, John Quarterman) Sun Nov  3 14:34:15 1985
619
 
 * Relay-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site gatech.CSNET
620
 
 * Posting-Version: version B 2.10.2 9/18/84; site ut-sally.UUCP
621
 
 * Path: gatech!akgua!mhuxv!mhuxt!mhuxr!ulysses!allegra!mit-eddie!genrad!panda!talcott!harvard!seismo!ut-sally!std-unix
622
 
 * From: std-unix@ut-sally.UUCP (Moderator, John Quarterman)
623
 
 * Newsgroups: mod.std.unix
624
 
 * Subject: public domain AT&T getopt source
625
 
 * Message-ID: <3352@ut-sally.UUCP>
626
 
 * Date: 3 Nov 85 19:34:15 GMT
627
 
 * Date-Received: 4 Nov 85 12:25:09 GMT
628
 
 * Organization: IEEE/P1003 Portable Operating System Environment Committee
629
 
 * Lines: 91
630
 
 * Approved: jsq@ut-sally.UUCP
631
 
 *
632
 
 * Here's something you've all been waiting for:  the AT&T public domain
633
 
 * source for getopt(3).  It is the code which was given out at the 1985
634
 
 * UNIFORUM conference in Dallas.  I obtained it by electronic mail
635
 
 * directly from AT&T.  The people there assure me that it is indeed
636
 
 * in the public domain.
637
 
 *
638
 
 * There is no manual page.  That is because the one they gave out at
639
 
 * UNIFORUM was slightly different from the current System V Release 2
640
 
 * manual page.  The difference apparently involved a note about the
641
 
 * famous rules 5 and 6, recommending using white space between an option
642
 
 * and its first argument, and not grouping options that have arguments.
643
 
 * Getopt itself is currently lenient about both of these things White
644
 
 * space is allowed, but not mandatory, and the last option in a group can
645
 
 * have an argument.  That particular version of the man page evidently
646
 
 * has no official existence, and my source at AT&T did not send a copy.
647
 
 * The current SVR2 man page reflects the actual behavor of this getopt.
648
 
 * However, I am not about to post a copy of anything licensed by AT&T.
649
 
 *
650
 
 * I will submit this source to Berkeley as a bug fix.
651
 
 *
652
 
 * I, personally, make no claims or guarantees of any kind about the
653
 
 * following source.  I did compile it to get some confidence that
654
 
 * it arrived whole, but beyond that you're on your own.
655
 
 *
656
 
 */
657
 
 
658
 
/*LINTLIBRARY*/
659
 
 
660
 
int     opterr = 1;
661
 
int     optind = 1;
662
 
int     optopt;
663
 
char    *optarg;
664
 
 
665
 
static void _ERR(s,c,argv)
666
 
char *s;
667
 
int c;
668
 
char *argv[];
669
 
{
670
 
        char errbuf[3];
671
 
 
672
 
        if (opterr) {
673
 
                errbuf[0] = c;
674
 
                errbuf[1] = '\n';
675
 
                (void) fprintf(stderr, "%s", argv[0]);
676
 
                (void) fprintf(stderr, "%s", s);
677
 
                (void) fprintf(stderr, "%s", errbuf);
678
 
        }
679
 
}
680
 
 
681
 
int getopt(argc, argv, opts)
682
 
int     argc;
683
 
char    **argv, *opts;
684
 
{
685
 
        static int sp = 1;
686
 
        register int c;
687
 
        register char *cp;
688
 
 
689
 
        if(sp == 1)
690
 
                if(optind >= argc ||
691
 
                   argv[optind][0] != '-' || argv[optind][1] == '\0')
692
 
                        return(EOF);
693
 
                else if(strcmp(argv[optind], "--") == 0) {
694
 
                        optind++;
695
 
                        return(EOF);
696
 
                }
697
 
        optopt = c = argv[optind][sp];
698
 
        if(c == ':' || (cp=strchr(opts, c)) == NULL) {
699
 
                _ERR(": illegal option -- ", c, argv);
700
 
                if(argv[optind][++sp] == '\0') {
701
 
                        optind++;
702
 
                        sp = 1;
703
 
                }
704
 
                return('?');
705
 
        }
706
 
        if(*++cp == ':') {
707
 
                if(argv[optind][sp+1] != '\0')
708
 
                        optarg = &argv[optind++][sp+1];
709
 
                else if(++optind >= argc) {
710
 
                        _ERR(": option requires an argument -- ", c, argv);
711
 
                        sp = 1;
712
 
                        return('?');
713
 
                } else
714
 
                        optarg = argv[optind++];
715
 
                sp = 1;
716
 
        } else {
717
 
                if(argv[optind][++sp] == '\0') {
718
 
                        sp = 1;
719
 
                        optind++;
720
 
                }
721
 
                optarg = NULL;
722
 
        }
723
 
        return(c);
724
 
}
725
 
 
726
 
#endif  /* !unix && !xenix */