dbug_analyze.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:19k
源码类别:

MySQL数据库

开发平台:

Visual C++

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