~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to dbug/dbug_analyze.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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 */