home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume30 / oraperl-v2 / part01 next >
Encoding:
Text File  |  1992-07-06  |  66.3 KB  |  2,643 lines

  1. Newsgroups: comp.sources.misc
  2. From: Kevin Stock <kstock@encore.com>
  3. Subject:  v30i087:  oraperl-v2 - Extensions to Perl to access Oracle database, Part01/05
  4. Message-ID: <csm-v30i087=oraperl-v2.133559@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: c6c232bb80a50c24de94debfee394c9a
  6. Date: Mon, 29 Jun 1992 18:37:20 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Kevin Stock <kstock@encore.com>
  10. Posting-number: Volume 30, Issue 87
  11. Archive-name: oraperl-v2/part01
  12. Environment: Perl, Oracle with OCI, optionally Curses
  13. Supersedes: oraperl: Volume 18, Issue 10
  14.  
  15. This is version 2 of Oraperl, a set of usersubs which allow Perl
  16. to access Oracle databases. You need Perl (v3.0.27 or better) and
  17. Oracle (including the Oracle Call Interface) to build Oraperl. If
  18. you can build Larry's Curseperl, then you can also build Coraperl,
  19. which is Oraperl with Curses.
  20.  
  21. The first version of Oraperl appeared in comp.sources.misc Volume
  22. 18, Issue 10, and was followed by five patches. This is a complete
  23. new release, not a patch.
  24.  
  25.   Principal changes:
  26.   ------------------
  27. The debugging code has been redone (again). I've finally done
  28. what I should have done long ago, and replaced all my debugging
  29. code with Fred Fish' excellent DBUG package. From now on, you can
  30. fine tune debugging traces.  See the file Debugging for details.
  31.  
  32. [ DBUG is in the public domain, and I highly recommend it. It's in ]
  33. [ the dbug/ subdirectory so you can install and use it separately. ]
  34.  
  35. The &ora_open() function now takes an optional third parameter which
  36. is the number of rows to cache from an SQL SELECT statement. Caching
  37. rows can lead to a significant increase in speed - see the file
  38. Row_cache for information regarding my tests. A new variable $ora_cache
  39. specifies the default cache size and may be set and tested in a program.
  40.  
  41. A bug in the &ora_open() function has been fixed. Previously, if the
  42. open failed for any reason, the memory allocated to the cursor was
  43. freed, but the Oracle library was not informed that the cursor had
  44. been released.  If this occurred several times in a program, it could
  45. lead to Oracle error 1000: "maximum open cursors exceeded". Now
  46. oclose() is called before freeing the cursor, removing the problem.
  47.  
  48. The first parameter to &ora_login() may now be an empty string
  49. (it may not be omitted) in which case Oraperl will work like
  50. other Oracle applications, and use the current value of ORACLE_SID
  51. to determine the database to use.
  52.  
  53. There is now support for LONG and LONGRAW datatypes. The variable
  54. $ora_long may be set to the buffer size to allocate for a LONG
  55. field - the default is 80, for compatibility with Oracle tools.
  56. An optional second parameter to &ora_fetch specifies whether a
  57. LONG field is allowed to be truncated. A new variable, $ora_trunc
  58. provides a default setting.
  59.  
  60.   Other changes:
  61.   --------------
  62. Since the OCI function obind requires that all bound values to be
  63. non-empty, ora_bind now replaces empty strings with a single
  64. space. If you do not want this behaviour, (ie, you prefer
  65. ora_bind to report an error for an empty string) define the
  66. symbol NO_BIND_PADDING during compilation.
  67.  
  68. A new function, &ora_autocommit, allows autocommit to be enabled
  69. or disabled per login.
  70.  
  71. A new function, &ora_lengths, returns an array containing the
  72. maximum length of each field returned by the specified query.
  73.  
  74. A new function, &ora_types, returns an array containing the Oracle
  75. datatype code for each field returned by the specified query.
  76.  
  77. A new variable, $ora_verno, reports the version number and
  78. patchlevel as (VERSION + PATCHLEVEL/1000); thus this version
  79. reports 2. This will allow scripts to distinguish between future
  80. versions. The format is chosen to be compatible with Perl's $]
  81. variable.
  82.  
  83. Fixed bugs when assigning and freeing cursors - I forgot to add
  84. code to initialise and free new fields which were introduced by
  85. various patches.
  86.  
  87. The &ora_version() function now reports the state of the following
  88. compile-time options: debugging, row cache size, bind padding.
  89.  
  90. If Oraperl is compiled without debugging code and run with the -w
  91. flag, an attempt to use or set $ora_debug will provoke a warning.
  92.  
  93. The Makefile now includes a test target. The tests are contained
  94. in testdir, and, to be honest, are far from exhaustive. However,
  95. if they work, it's a good sign!
  96.  
  97. The Makefile now also includes an install target, which runs the
  98. install.pl script provided. This is a hacked version of Larry's
  99. installperl, so it will install oraperl (and coraperl if it exists)
  100. in the same place as Perl. The sql script is also installed.
  101.  
  102. The Oracle-v5 file has been merged into the Hints file.
  103.  
  104. The files have been reorganised into a set of subdirectories.
  105.  
  106. &ora_login now uses Perl's my_setenv() function to choose the database.
  107.  
  108. The documentation has been rewritten.
  109.  
  110. (My thanks to Brian Brogmus for the inspiration behind several
  111. of these changes and additions.)
  112.  
  113.   What to do
  114.   ----------
  115. Unshar these files somewhere convenient and look through the
  116. README file for configuration information. Set up the
  117. configuration you want in Makefile, then run make. Have a read
  118. through the documentation while you're waiting.
  119. ----
  120. #! /bin/sh
  121. # This is a shell archive.  Remove anything before this line, then feed it
  122. # into a shell via "sh file" or similar.  To overwrite existing files,
  123. # type "sh file -c".
  124. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  125. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  126. # Contents:  dbug dbug/dbug.c dbug/dbug.qr doc examples oracle.mus
  127. #   testdir
  128. # Wrapped by kent@sparky on Mon Jun 29 13:23:36 1992
  129. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  130. echo If this archive is complete, you will see the following message:
  131. echo '          "shar: End of archive 1 (of 5)."'
  132. if test ! -d 'dbug' ; then
  133.     echo shar: Creating directory \"'dbug'\"
  134.     mkdir 'dbug'
  135. fi
  136. if test -f 'dbug/dbug.c' -a "${1}" != "-c" ; then 
  137.   echo shar: Will not clobber existing file \"'dbug/dbug.c'\"
  138. else
  139.   echo shar: Extracting \"'dbug/dbug.c'\" \(44504 characters\)
  140.   sed "s/^X//" >'dbug/dbug.c' <<'END_OF_FILE'
  141. X/******************************************************************************
  142. X *                                          *
  143. X *                               N O T I C E                      *
  144. X *                                          *
  145. X *                  Copyright Abandoned, 1987, Fred Fish              *
  146. X *                                          *
  147. X *                                          *
  148. X *    This previously copyrighted work has been placed into the  public     *
  149. X *    domain  by  the  author  and  may be freely used for any purpose,     *
  150. X *    private or commercial.                              *
  151. X *                                          *
  152. X *    Because of the number of inquiries I was receiving about the  use     *
  153. X *    of this product in commercially developed works I have decided to     *
  154. X *    simply make it public domain to further its unrestricted use.   I     *
  155. X *    specifically  would  be  most happy to see this material become a     *
  156. X *    part of the standard Unix distributions by AT&T and the  Berkeley     *
  157. X *    Computer  Science  Research Group, and a standard part of the GNU     *
  158. X *    system from the Free Software Foundation.                  *
  159. X *                                          *
  160. X *    I would appreciate it, as a courtesy, if this notice is  left  in     *
  161. X *    all copies and derivative works.  Thank you.                  *
  162. X *                                          *
  163. X *    The author makes no warranty of any kind  with  respect  to  this     *
  164. X *    product  and  explicitly disclaims any implied warranties of mer-     *
  165. X *    chantability or fitness for any particular purpose.              *
  166. X *                                          *
  167. X ******************************************************************************
  168. X */
  169. X
  170. X
  171. X/*
  172. X *  FILE
  173. X *
  174. X *    dbug.c   runtime support routines for dbug package
  175. X *
  176. X *  SCCS
  177. X *
  178. X *    @(#)dbug.c    1.19 9/5/87
  179. X *
  180. X *  DESCRIPTION
  181. X *
  182. X *    These are the runtime support routines for the dbug package.
  183. X *    The dbug package has two main components; the user include
  184. X *    file containing various macro definitions, and the runtime
  185. X *    support routines which are called from the macro expansions.
  186. X *
  187. X *    Externally visible functions in the runtime support module
  188. X *    use the naming convention pattern "_db_xx...xx_", thus
  189. X *    they are unlikely to collide with user defined function names.
  190. X *
  191. X *  AUTHOR(S)
  192. X *
  193. X *    Fred Fish        (base code)
  194. X *    (Currently at Motorola Computer Division, Tempe, Az.)
  195. X *    hao!noao!mcdsun!fnf
  196. X *    (602) 438-3614
  197. X *
  198. X *    Binayak Banerjee    (profiling enhancements)
  199. X *    seismo!bpa!sjuvax!bbanerje
  200. X */
  201. X
  202. X
  203. X#include <stdio.h>
  204. X#ifdef amiga
  205. X#define AMIGA
  206. X#endif
  207. X
  208. X#ifdef AMIGA
  209. X#define HZ (50)            /* Probably in some header somewhere */
  210. X#endif
  211. X
  212. X/*
  213. X *    Manifest constants that should not require any changes.
  214. X */
  215. X
  216. X#define FALSE        0    /* Boolean FALSE */
  217. X#define TRUE        1    /* Boolean TRUE */
  218. X#define EOS        '\000'    /* End Of String marker */
  219. X
  220. X/*
  221. X *    Manifest constants which may be "tuned" if desired.
  222. X */
  223. X
  224. X#define PRINTBUF    1024    /* Print buffer size */
  225. X#define INDENT        4    /* Indentation per trace level */
  226. X#define MAXDEPTH    200    /* Maximum trace depth default */
  227. X
  228. X/*
  229. X *    The following flags are used to determine which
  230. X *    capabilities the user has enabled with the state
  231. X *    push macro.
  232. X */
  233. X
  234. X#define TRACE_ON    000001    /* Trace enabled */
  235. X#define DEBUG_ON    000002    /* Debug enabled */
  236. X#define FILE_ON     000004    /* File name print enabled */
  237. X#define LINE_ON        000010    /* Line number print enabled */
  238. X#define DEPTH_ON    000020    /* Function nest level print enabled */
  239. X#define PROCESS_ON    000040    /* Process name print enabled */
  240. X#define NUMBER_ON    000100    /* Number each line of output */
  241. X#define PROFILE_ON    000200    /* Print out profiling code */
  242. X
  243. X#define TRACING (stack -> flags & TRACE_ON)
  244. X#define DEBUGGING (stack -> flags & DEBUG_ON)
  245. X#define PROFILING (stack -> flags & PROFILE_ON)
  246. X#define STREQ(a,b) (strcmp(a,b) == 0)
  247. X
  248. X/*
  249. X *    Typedefs to make things more obvious.
  250. X */
  251. X
  252. X#define VOID void        /* Can't use typedef for most compilers */
  253. Xtypedef int BOOLEAN;
  254. X
  255. X/*
  256. X *    Make it easy to change storage classes if necessary.
  257. X */
  258. X
  259. X#define LOCAL static        /* Names not needed by outside world */
  260. X#define IMPORT extern        /* Names defined externally */
  261. X#define EXPORT            /* Allocated here, available globally */
  262. X#define AUTO auto        /* Names to be allocated on stack */
  263. X#define REGISTER register    /* Names to be placed in registers */
  264. X
  265. X/*
  266. X *    The following define is for the variable arguments kluge, see
  267. X *    the comments in _db_doprnt_().
  268. X *
  269. X *    Also note that the longer this list, the less prone to failing
  270. X *    on long argument lists, but the more stuff that must be moved
  271. X *    around for each call to the runtime support routines.  The
  272. X *    length may really be critical if the machine convention is
  273. X *    to pass arguments in registers.
  274. X *
  275. X *    Note that the default define allows up to 16 integral arguments,
  276. X *    or 8 floating point arguments (doubles), on most machines.
  277. X *
  278. X *    Someday this may be replaced with true varargs support, when
  279. X *    ANSI C has had time to take root.
  280. X */
  281. X
  282. X#define ARGLIST a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15
  283. X
  284. X/*
  285. X * The default file for profiling.  Could also add another flag
  286. X * (G?) which allowed the user to specify this.
  287. X */
  288. X
  289. X#define PROF_FILE    "dbugmon.out"
  290. X
  291. X/*
  292. X *    Variables which are available externally but should only
  293. X *    be accessed via the macro package facilities.
  294. X */
  295. X
  296. XEXPORT FILE *_db_fp_ = stderr;        /* Output stream, default stderr */
  297. XEXPORT FILE *_db_pfp_ = (FILE *)0;    /* Profile stream, 'dbugmon.out' */
  298. XEXPORT char *_db_process_ = "dbug";    /* Pointer to process name; argv[0] */
  299. XEXPORT BOOLEAN _db_on_ = FALSE;        /* TRUE if debugging currently on */
  300. XEXPORT BOOLEAN _db_pon_ = FALSE;    /* TRUE if debugging currently on */
  301. X
  302. X/*
  303. X *    Externally supplied functions.
  304. X */
  305. X
  306. X#ifdef unix            /* Only needed for unix */
  307. XIMPORT VOID perror ();        /* Print system/library error */
  308. XIMPORT int chown ();        /* Change owner of a file */
  309. XIMPORT int getgid ();        /* Get real group id */
  310. XIMPORT int getuid ();        /* Get real user id */
  311. XIMPORT int access ();        /* Test file for access */
  312. X#else
  313. X#if !(AMIGA || LATTICE || __TURBOC__)
  314. XLOCAL VOID perror ();        /* Fake system/library error print routine */
  315. X#endif
  316. X#endif
  317. X
  318. X# if BSD4_3 || sun
  319. XIMPORT int getrusage ();
  320. X#endif
  321. X
  322. XIMPORT int atoi ();        /* Convert ascii to integer */
  323. XIMPORT VOID exit ();        /* Terminate execution */
  324. XIMPORT int fclose ();        /* Close a stream */
  325. XIMPORT FILE *fopen ();        /* Open a stream */
  326. X#if !defined(__BORLANDC__)
  327. XIMPORT int fprintf ();        /* Formatted print on file */
  328. X#endif
  329. XIMPORT VOID free ();
  330. XIMPORT char *malloc ();        /* Allocate memory */
  331. XIMPORT int strcmp ();        /* Compare strings */
  332. XIMPORT char *strcpy ();        /* Copy strings around */
  333. XIMPORT int strlen ();        /* Find length of string */
  334. X
  335. X#ifndef fflush            /* This is sometimes a macro */
  336. XIMPORT int fflush ();        /* Flush output for stream */
  337. X#endif
  338. X
  339. X
  340. X/*
  341. X *    The user may specify a list of functions to trace or 
  342. X *    debug.  These lists are kept in a linear linked list,
  343. X *    a very simple implementation.
  344. X */
  345. X
  346. Xstruct link {
  347. X    char *string;        /* Pointer to link's contents */
  348. X    struct link *next_link;    /* Pointer to the next link */
  349. X};
  350. X
  351. X
  352. X/*
  353. X *    Debugging states can be pushed or popped off of a
  354. X *    stack which is implemented as a linked list.  Note
  355. X *    that the head of the list is the current state and the
  356. X *    stack is pushed by adding a new state to the head of the
  357. X *    list or popped by removing the first link.
  358. X */
  359. X
  360. Xstruct state {
  361. X    int flags;                /* Current state flags */
  362. X    int maxdepth;            /* Current maximum trace depth */
  363. X    unsigned int delay;            /* Delay after each output line */
  364. X    int level;                /* Current function nesting level */
  365. X    FILE *out_file;            /* Current output stream */
  366. X    FILE *prof_file;            /* Current profiling stream */
  367. X    struct link *functions;        /* List of functions */
  368. X    struct link *p_functions;        /* List of profiled functions */
  369. X    struct link *keywords;        /* List of debug keywords */
  370. X    struct link *processes;        /* List of process names */
  371. X    struct state *next_state;        /* Next state in the list */
  372. X};
  373. X
  374. XLOCAL struct state *stack = NULL;    /* Linked list of stacked states */
  375. X
  376. X/*
  377. X *    Local variables not seen by user.
  378. X */
  379. X
  380. XLOCAL int lineno = 0;        /* Current debugger output line number */
  381. XLOCAL char *func = "?func";    /* Name of current user function */
  382. XLOCAL char *file = "?file";    /* Name of current user file */
  383. XLOCAL BOOLEAN init_done = FALSE;/* Set to TRUE when initialization done */
  384. X
  385. X/*#if unix || AMIGA || M_I86*/
  386. XLOCAL int jmplevel;        /* Remember nesting level at setjmp () */
  387. XLOCAL char *jmpfunc;        /* Remember current function for setjmp */
  388. XLOCAL char *jmpfile;        /* Remember current file for setjmp */
  389. X/*#endif*/
  390. X
  391. XLOCAL struct link *ListParse ();/* Parse a debug command string */
  392. XLOCAL char *StrDup ();        /* Make a fresh copy of a string */
  393. XLOCAL VOID OpenFile ();        /* Open debug output stream */
  394. XLOCAL VOID OpenProfile ();    /* Open profile output stream */
  395. XLOCAL VOID CloseFile ();    /* Close debug output stream */
  396. XLOCAL VOID PushState ();    /* Push current debug state */
  397. XLOCAL VOID ChangeOwner ();    /* Change file owner and group */
  398. XLOCAL BOOLEAN DoTrace ();    /* Test for tracing enabled */
  399. XLOCAL BOOLEAN Writable ();    /* Test to see if file is writable */
  400. XLOCAL unsigned long Clock ();    /* Return current user time (ms) */
  401. XLOCAL char *DbugMalloc ();    /* Allocate memory for runtime support */
  402. XLOCAL char *BaseName ();    /* Remove leading pathname components */
  403. XLOCAL VOID DoPrefix ();        /* Print debugger line prefix */
  404. XLOCAL VOID FreeList ();        /* Free memory from linked list */
  405. XLOCAL VOID Indent ();        /* Indent line to specified indent */
  406. X
  407. X                /* Supplied in Sys V runtime environ */
  408. XLOCAL char *strtok ();        /* Break string into tokens */
  409. XLOCAL char *strrchr ();        /* Find last occurance of char */
  410. X
  411. X/*
  412. X *    The following local variables are used to hold the state information
  413. X *    between the call to _db_pargs_() and _db_doprnt_(), during
  414. X *    expansion of the DBUG_PRINT macro.  This is the only macro
  415. X *    that currently uses these variables.  The DBUG_PRINT macro
  416. X *    and the new _db_doprnt_() routine replace the older DBUG_N macros
  417. X *    and their corresponding runtime support routine _db_printf_().
  418. X *
  419. X *    These variables are currently used only by _db_pargs_() and
  420. X *    _db_doprnt_().
  421. X */
  422. X
  423. XLOCAL int u_line = 0;        /* User source code line number */
  424. XLOCAL char *u_keyword = "?";    /* Keyword for current macro */
  425. X
  426. X/*
  427. X *    Miscellaneous printf format strings.
  428. X */
  429. X#define ERR_MISSING_RETURN "%s: missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
  430. X#define ERR_OPEN "%s: can't open debug output stream \"%s\": "
  431. X#define ERR_CLOSE "%s: can't close debug file: "
  432. X#define ERR_ABORT "%s: debugger aborting because %s\n"
  433. X#define ERR_CHOWN "%s: can't change owner/group of \"%s\": "
  434. X#define ERR_PRINTF "%s: obsolete object file for '%s', please recompile!\n"
  435. X
  436. X/*
  437. X *    Macros and defines for testing file accessibility under UNIX.
  438. X */
  439. X
  440. X#ifdef unix
  441. X#  define A_EXISTS    00        /* Test for file existance */
  442. X#  define A_EXECUTE    01        /* Test for execute permission */
  443. X#  define A_WRITE    02        /* Test for write access */
  444. X#  define A_READ    03        /* Test for read access */
  445. X#  define EXISTS(pathname) (access (pathname, A_EXISTS) == 0)
  446. X#  define WRITABLE(pathname) (access (pathname, A_WRITE) == 0)
  447. X#else
  448. X#  define EXISTS(pathname) (FALSE)    /* Assume no existance */
  449. X#endif
  450. X
  451. X/*
  452. X *    Translate some calls among different systems.
  453. X */
  454. X
  455. X#ifdef unix
  456. X# define XDelay sleep
  457. XIMPORT unsigned int sleep ();    /* Pause for given number of seconds */
  458. X#endif
  459. X
  460. X#ifdef AMIGA
  461. XIMPORT int XDelay ();        /* Pause for given number of ticks */
  462. X#endif
  463. X
  464. X
  465. X/*
  466. X *  FUNCTION
  467. X *
  468. X *    _db_push_    push current debugger state and set up new one
  469. X *
  470. X *  SYNOPSIS
  471. X *
  472. X *    VOID _db_push_ (control)
  473. X *    char *control;
  474. X *
  475. X *  DESCRIPTION
  476. X *
  477. X *    Given pointer to a debug control string in "control", pushes
  478. X *    the current debug state, parses the control string, and sets
  479. X *    up a new debug state.
  480. X *
  481. X *    The only attribute of the new state inherited from the previous
  482. X *    state is the current function nesting level.  This can be
  483. X *    overridden by using the "r" flag in the control string.
  484. X *
  485. X *    The debug control string is a sequence of colon separated fields
  486. X *    as follows:
  487. X *
  488. X *        <field_1>:<field_2>:...:<field_N>
  489. X *
  490. X *    Each field consists of a mandatory flag character followed by
  491. X *    an optional "," and comma separated list of modifiers:
  492. X *
  493. X *        flag[,modifier,modifier,...,modifier]
  494. X *
  495. X *    The currently recognized flag characters are:
  496. X *
  497. X *        d    Enable output from DBUG_<N> macros for
  498. X *            for the current state.  May be followed
  499. X *            by a list of keywords which selects output
  500. X *            only for the DBUG macros with that keyword.
  501. X *            A null list of keywords implies output for
  502. X *            all macros.
  503. X *
  504. X *        D    Delay after each debugger output line.
  505. X *            The argument is the number of tenths of seconds
  506. X *            to delay, subject to machine capabilities.
  507. X *            I.E.  -#D,20 is delay two seconds.
  508. X *
  509. X *        f    Limit debugging and/or tracing, and profiling to the
  510. X *            list of named functions.  Note that a null list will
  511. X *            disable all functions.  The appropriate "d" or "t"
  512. X *            flags must still be given, this flag only limits their
  513. X *            actions if they are enabled.
  514. X *
  515. X *        F    Identify the source file name for each
  516. X *            line of debug or trace output.
  517. X *
  518. X *        g    Enable profiling.  Create a file called 'dbugmon.out'
  519. X *            containing information that can be used to profile
  520. X *            the program.  May be followed by a list of keywords
  521. X *            that select profiling only for the functions in that
  522. X *            list.  A null list implies that all functions are
  523. X *            considered.
  524. X *
  525. X *        L    Identify the source file line number for
  526. X *            each line of debug or trace output.
  527. X *
  528. X *        n    Print the current function nesting depth for
  529. X *            each line of debug or trace output.
  530. X *    
  531. X *        N    Number each line of dbug output.
  532. X *
  533. X *        p    Limit debugger actions to specified processes.
  534. X *            A process must be identified with the
  535. X *            DBUG_PROCESS macro and match one in the list
  536. X *            for debugger actions to occur.
  537. X *
  538. X *        P    Print the current process name for each
  539. X *            line of debug or trace output.
  540. X *
  541. X *        r    When pushing a new state, do not inherit
  542. X *            the previous state's function nesting level.
  543. X *            Useful when the output is to start at the
  544. X *            left margin.
  545. X *
  546. X *        t    Enable function call/exit trace lines.
  547. X *            May be followed by a list (containing only
  548. X *            one modifier) giving a numeric maximum
  549. X *            trace level, beyond which no output will
  550. X *            occur for either debugging or tracing
  551. X *            macros.  The default is a compile time
  552. X *            option.
  553. X *
  554. X *    Some examples of debug control strings which might appear
  555. X *    on a shell command line (the "-#" is typically used to
  556. X *    introduce a control string to an application program) are:
  557. X *
  558. X *        -#d:t
  559. X *        -#d:f,main,subr1:F:L:t,20
  560. X *        -#d,input,output,files:n
  561. X *
  562. X *    For convenience, any leading "-#" is stripped off.
  563. X *
  564. X */
  565. X
  566. X
  567. XVOID _db_push_ (control)
  568. Xchar *control;
  569. X{
  570. X    REGISTER char *scan;
  571. X    REGISTER struct link *temp;
  572. X
  573. X    if (control && *control == '-') {
  574. X    if (*++control == '#') {
  575. X        control++;
  576. X    }    
  577. X    }
  578. X    control = StrDup (control);
  579. X    PushState ();
  580. X    scan = strtok (control, ":");
  581. X    for (; scan != NULL; scan = strtok ((char *)NULL, ":")) {
  582. X    switch (*scan++) {
  583. X        case 'd': 
  584. X        _db_on_ = TRUE;
  585. X        stack -> flags |= DEBUG_ON;
  586. X        if (*scan++ == ',') {
  587. X            stack -> keywords = ListParse (scan);
  588. X        }
  589. X            break;
  590. X        case 'D': 
  591. X        stack -> delay = 0;
  592. X        if (*scan++ == ',') {
  593. X            temp = ListParse (scan);
  594. X            stack -> delay = DelayArg (atoi (temp -> string));
  595. X            FreeList (temp);
  596. X        }
  597. X        break;
  598. X        case 'f': 
  599. X        if (*scan++ == ',') {
  600. X            stack -> functions = ListParse (scan);
  601. X        }
  602. X        break;
  603. X        case 'F': 
  604. X        stack -> flags |= FILE_ON;
  605. X        break;
  606. X        case 'g': 
  607. X        _db_pon_ = TRUE;
  608. X        OpenProfile(PROF_FILE);
  609. X        stack -> flags |= PROFILE_ON;
  610. X        if (*scan++ == ',') {
  611. X            stack -> p_functions = ListParse (scan);
  612. X        }
  613. X        break;
  614. X        case 'L': 
  615. X        stack -> flags |= LINE_ON;
  616. X        break;
  617. X        case 'n': 
  618. X        stack -> flags |= DEPTH_ON;
  619. X        break;
  620. X        case 'N':
  621. X        stack -> flags |= NUMBER_ON;
  622. X        break;
  623. X        case 'o': 
  624. X        if (*scan++ == ',') {
  625. X            temp = ListParse (scan);
  626. X            OpenFile (temp -> string);
  627. X            FreeList (temp);
  628. X        } else {
  629. X            OpenFile ("-");
  630. X        }
  631. X        break;
  632. X        case 'p':
  633. X        if (*scan++ == ',') {
  634. X            stack -> processes = ListParse (scan);
  635. X        }
  636. X        break;
  637. X        case 'P': 
  638. X        stack -> flags |= PROCESS_ON;
  639. X        break;
  640. X        case 'r': 
  641. X        stack -> level = 0;
  642. X        break;
  643. X        case 't': 
  644. X        stack -> flags |= TRACE_ON;
  645. X        if (*scan++ == ',') {
  646. X            temp = ListParse (scan);
  647. X            stack -> maxdepth = atoi (temp -> string);
  648. X            FreeList (temp);
  649. X        }
  650. X        break;
  651. X    }
  652. X    }
  653. X    free (control);
  654. X}
  655. X
  656. X
  657. X
  658. X/*
  659. X *  FUNCTION
  660. X *
  661. X *    _db_pop_    pop the debug stack
  662. X *
  663. X *  DESCRIPTION
  664. X *
  665. X *    Pops the debug stack, returning the debug state to its
  666. X *    condition prior to the most recent _db_push_ invocation.
  667. X *    Note that the pop will fail if it would remove the last
  668. X *    valid state from the stack.  This prevents user errors
  669. X *    in the push/pop sequence from screwing up the debugger.
  670. X *    Maybe there should be some kind of warning printed if the
  671. X *    user tries to pop too many states.
  672. X *
  673. X */
  674. X
  675. XVOID _db_pop_ ()
  676. X{
  677. X    REGISTER struct state *discard;
  678. X
  679. X    discard = stack;
  680. X    if (discard != NULL && discard -> next_state != NULL) {
  681. X    stack = discard -> next_state;
  682. X    _db_fp_ = stack -> out_file;
  683. X    _db_pfp_ = stack -> prof_file;
  684. X    if (discard -> keywords != NULL) {
  685. X        FreeList (discard -> keywords);
  686. X    }
  687. X    if (discard -> functions != NULL) {
  688. X        FreeList (discard -> functions);
  689. X    }
  690. X    if (discard -> processes != NULL) {
  691. X        FreeList (discard -> processes);
  692. X    }
  693. X    if (discard -> p_functions != NULL) {
  694. X        FreeList (discard -> p_functions);
  695. X    }
  696. X    CloseFile (discard -> out_file);
  697. X    CloseFile (discard -> prof_file);
  698. X    free ((char *) discard);
  699. X    }
  700. X}
  701. X
  702. X
  703. X/*
  704. X *  FUNCTION
  705. X *
  706. X *    _db_enter_    process entry point to user function
  707. X *
  708. X *  SYNOPSIS
  709. X *
  710. X *    VOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_)
  711. X *    char *_func_;        points to current function name
  712. X *    char *_file_;        points to current file name
  713. X *    int _line_;        called from source line number
  714. X *    char **_sfunc_;        save previous _func_
  715. X *    char **_sfile_;        save previous _file_
  716. X *    int *_slevel_;        save previous nesting level
  717. X *
  718. X *  DESCRIPTION
  719. X *
  720. X *    Called at the beginning of each user function to tell
  721. X *    the debugger that a new function has been entered.
  722. X *    Note that the pointers to the previous user function
  723. X *    name and previous user file name are stored on the
  724. X *    caller's stack (this is why the ENTER macro must be
  725. X *    the first "executable" code in a function, since it
  726. X *    allocates these storage locations).  The previous nesting
  727. X *    level is also stored on the callers stack for internal
  728. X *    self consistency checks.
  729. X *
  730. X *    Also prints a trace line if tracing is enabled and
  731. X *    increments the current function nesting depth.
  732. X *
  733. X *    Note that this mechanism allows the debugger to know
  734. X *    what the current user function is at all times, without
  735. X *    maintaining an internal stack for the function names.
  736. X *
  737. X */
  738. X
  739. XVOID _db_enter_ (_func_, _file_, _line_, _sfunc_, _sfile_, _slevel_)
  740. Xchar *_func_;
  741. Xchar *_file_;
  742. Xint _line_;
  743. Xchar **_sfunc_;
  744. Xchar **_sfile_;
  745. Xint *_slevel_;
  746. X{
  747. X    if (!init_done) {
  748. X    _db_push_ ("");
  749. X    }
  750. X    *_sfunc_ = func;
  751. X    *_sfile_ = file;
  752. X    func = _func_;
  753. X    file = BaseName (_file_);
  754. X    stack -> level++;
  755. X    *_slevel_ = stack -> level;
  756. X    if (DoProfile ()) {
  757. X    (VOID) fprintf (_db_pfp_, "%s\tE\t%ld\n",func, Clock());
  758. X    (VOID) fflush (_db_pfp_);
  759. X    }
  760. X    if (DoTrace ()) {
  761. X    DoPrefix (_line_);
  762. X    Indent (stack -> level);
  763. X    (VOID) fprintf (_db_fp_, ">%s\n", func);
  764. X    (VOID) fflush (_db_fp_);
  765. X    (VOID) XDelay (stack -> delay);
  766. X    }
  767. X}
  768. X
  769. X
  770. X/*
  771. X *  FUNCTION
  772. X *
  773. X *    _db_return_    process exit from user function
  774. X *
  775. X *  SYNOPSIS
  776. X *
  777. X *    VOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
  778. X *    int _line_;        current source line number
  779. X *    char **_sfunc_;        where previous _func_ is to be retrieved
  780. X *    char **_sfile_;        where previous _file_ is to be retrieved
  781. X *    int *_slevel_;        where previous level was stashed
  782. X *
  783. X *  DESCRIPTION
  784. X *
  785. X *    Called just before user function executes an explicit or implicit
  786. X *    return.  Prints a trace line if trace is enabled, decrements
  787. X *    the current nesting level, and restores the current function and
  788. X *    file names from the defunct function's stack.
  789. X *
  790. X */
  791. X
  792. XVOID _db_return_ (_line_, _sfunc_, _sfile_, _slevel_)
  793. Xint _line_;
  794. Xchar **_sfunc_;
  795. Xchar **_sfile_;
  796. Xint *_slevel_;
  797. X{
  798. X    if (!init_done) {
  799. X    _db_push_ ("");
  800. X    }
  801. X    if (stack -> level != *_slevel_ && (TRACING || DEBUGGING || PROFILING)) {
  802. X    (VOID) fprintf (_db_fp_, ERR_MISSING_RETURN, _db_process_, func);
  803. X        (VOID) XDelay (stack -> delay);
  804. X    } else if (DoProfile ()) {
  805. X    (VOID) fprintf (_db_pfp_, "%s\tX\t%ld\n", func, Clock());
  806. X        (VOID) XDelay (stack -> delay);
  807. X    } else if (DoTrace ()) {
  808. X    DoPrefix (_line_);
  809. X    Indent (stack -> level);
  810. X    (VOID) fprintf (_db_fp_, "<%s\n", func);
  811. X        (VOID) XDelay (stack -> delay);
  812. X    }
  813. X    (VOID) fflush (_db_fp_);
  814. X    stack -> level = *_slevel_ - 1;
  815. X    func = *_sfunc_;
  816. X    file = *_sfile_;
  817. X}
  818. X
  819. X
  820. X/*
  821. X *  FUNCTION
  822. X *
  823. X *    _db_pargs_    log arguments for subsequent use by _db_doprnt_()
  824. X *
  825. X *  SYNOPSIS
  826. X *
  827. X *    VOID _db_pargs_ (_line_, keyword)
  828. X *    int _line_;
  829. X *    char *keyword;
  830. X *
  831. X *  DESCRIPTION
  832. X *
  833. X *    The new universal printing macro DBUG_PRINT, which replaces
  834. X *    all forms of the DBUG_N macros, needs two calls to runtime
  835. X *    support routines.  The first, this function, remembers arguments
  836. X *    that are used by the subsequent call to _db_doprnt_().
  837. X*
  838. X */
  839. X
  840. XVOID _db_pargs_ (_line_, keyword)
  841. Xint _line_;
  842. Xchar *keyword;
  843. X{
  844. X    u_line = _line_;
  845. X    u_keyword = keyword;
  846. X}
  847. X
  848. X
  849. X/*
  850. X *  FUNCTION
  851. X *
  852. X *    _db_doprnt_    handle print of debug lines
  853. X *
  854. X *  SYNOPSIS
  855. X *
  856. X *    VOID _db_doprnt_ (format, ARGLIST)
  857. X *    char *format;
  858. X *    long ARGLIST;
  859. X *
  860. X *  DESCRIPTION
  861. X *
  862. X *    When invoked via one of the DBUG macros, tests the current keyword
  863. X *    set by calling _db_pargs_() to see if that macro has been selected
  864. X *    for processing via the debugger control string, and if so, handles
  865. X *    printing of the arguments via the format string.  The line number
  866. X *    of the DBUG macro in the source is found in u_line.
  867. X *
  868. X *    Note that the format string SHOULD NOT include a terminating
  869. X *    newline, this is supplied automatically.
  870. X *
  871. X *  NOTES
  872. X *
  873. X *    This runtime support routine replaces the older _db_printf_()
  874. X *    routine which is temporarily kept around for compatibility.
  875. X *
  876. X *    The rather ugly argument declaration is to handle some
  877. X *    magic with respect to the number of arguments passed
  878. X *    via the DBUG macros.  The current maximum is 3 arguments
  879. X *    (not including the keyword and format strings).
  880. X *
  881. X *    The new <varargs.h> facility is not yet common enough to
  882. X *    convert to it quite yet...
  883. X *
  884. X */
  885. X
  886. X/*VARARGS1*/
  887. XVOID _db_doprnt_ (format, ARGLIST)
  888. Xchar *format;
  889. Xlong ARGLIST;
  890. X{
  891. X    if (_db_keyword_ (u_keyword)) {
  892. X    DoPrefix (u_line);
  893. X    if (TRACING) {
  894. X        Indent (stack -> level + 1);
  895. X    } else {
  896. X        (VOID) fprintf (_db_fp_, "%s: ", func);
  897. X    }
  898. X    (VOID) fprintf (_db_fp_, "%s: ", u_keyword);
  899. X    (VOID) fprintf (_db_fp_, format, ARGLIST);
  900. X    (VOID) fprintf (_db_fp_, "\n");
  901. X    (VOID) fflush (_db_fp_);
  902. X    (VOID) XDelay (stack -> delay);
  903. X    }
  904. X}
  905. X
  906. X/*
  907. X *    The following routine is kept around temporarily for compatibility
  908. X *    with older objects that were compiled with the DBUG_N macro form
  909. X *    of the print routine.  It will print a warning message on first
  910. X *    usage.  It will go away in subsequent releases...
  911. X */
  912. X
  913. X/*VARARGS3*/
  914. XVOID _db_printf_ (_line_, keyword, format, ARGLIST)
  915. Xint _line_;
  916. Xchar *keyword,  *format;
  917. Xlong ARGLIST;
  918. X{
  919. X    static BOOLEAN firsttime = TRUE;
  920. X
  921. X    if (firsttime) {
  922. X    (VOID) fprintf (stderr, ERR_PRINTF, _db_process_, file);
  923. X    firsttime = FALSE;
  924. X    }
  925. X    _db_pargs_ (_line_, keyword);
  926. X    _db_doprnt_ (format, ARGLIST);
  927. X}
  928. X
  929. X
  930. X/*
  931. X *  FUNCTION
  932. X *
  933. X *    ListParse    parse list of modifiers in debug control string
  934. X *
  935. X *  SYNOPSIS
  936. X *
  937. X *    LOCAL struct link *ListParse (ctlp)
  938. X *    char *ctlp;
  939. X *
  940. X *  DESCRIPTION
  941. X *
  942. X *    Given pointer to a comma separated list of strings in "cltp",
  943. X *    parses the list, building a list and returning a pointer to it.
  944. X *    The original comma separated list is destroyed in the process of
  945. X *    building the linked list, thus it had better be a duplicate
  946. X *    if it is important.
  947. X *
  948. X *    Note that since each link is added at the head of the list,
  949. X *    the final list will be in "reverse order", which is not
  950. X *    significant for our usage here.
  951. X *
  952. X */
  953. X
  954. XLOCAL struct link *ListParse (ctlp)
  955. Xchar *ctlp;
  956. X{
  957. X    REGISTER char *start;
  958. X    REGISTER struct link *new;
  959. X    REGISTER struct link *head;
  960. X
  961. X    head = NULL;
  962. X    while (*ctlp != EOS) {
  963. X    start = ctlp;
  964. X    while (*ctlp != EOS && *ctlp != ',') {
  965. X        ctlp++;
  966. X    }
  967. X    if (*ctlp == ',') {
  968. X        *ctlp++ = EOS;
  969. X    }
  970. X    new = (struct link *) DbugMalloc (sizeof (struct link));
  971. X    new -> string = StrDup (start);
  972. X    new -> next_link = head;
  973. X    head = new;
  974. X    }
  975. X    return (head);
  976. X}
  977. X
  978. X
  979. X/*
  980. X *  FUNCTION
  981. X *
  982. X *    InList    test a given string for member of a given list
  983. X *
  984. X *  SYNOPSIS
  985. X *
  986. X *    LOCAL BOOLEAN InList (linkp, cp)
  987. X *    struct link *linkp;
  988. X *    char *cp;
  989. X *
  990. X *  DESCRIPTION
  991. X *
  992. X *    Tests the string pointed to by "cp" to determine if it is in
  993. X *    the list pointed to by "linkp".  Linkp points to the first
  994. X *    link in the list.  If linkp is NULL then the string is treated
  995. X *    as if it is in the list (I.E all strings are in the null list).
  996. X *    This may seem rather strange at first but leads to the desired
  997. X *    operation if no list is given.  The net effect is that all
  998. X *    strings will be accepted when there is no list, and when there
  999. X *    is a list, only those strings in the list will be accepted.
  1000. X *
  1001. X */
  1002. X
  1003. XLOCAL BOOLEAN InList (linkp, cp)
  1004. Xstruct link *linkp;
  1005. Xchar *cp;
  1006. X{
  1007. X    REGISTER struct link *scan;
  1008. X    REGISTER BOOLEAN accept;
  1009. X
  1010. X    if (linkp == NULL) {
  1011. X    accept = TRUE;
  1012. X    } else {
  1013. X    accept = FALSE;
  1014. X    for (scan = linkp; scan != NULL; scan = scan -> next_link) {
  1015. X        if (STREQ (scan -> string, cp)) {
  1016. X        accept = TRUE;
  1017. X        break;
  1018. X        }
  1019. X    }
  1020. X    }
  1021. X    return (accept);
  1022. X}
  1023. X
  1024. X
  1025. X/*
  1026. X *  FUNCTION
  1027. X *
  1028. X *    PushState    push current state onto stack and set up new one
  1029. X *
  1030. X *  SYNOPSIS
  1031. X *
  1032. X *    LOCAL VOID PushState ()
  1033. X *
  1034. X *  DESCRIPTION
  1035. X *
  1036. X *    Pushes the current state on the state stack, and initializes
  1037. X *    a new state.  The only parameter inherited from the previous
  1038. X *    state is the function nesting level.  This action can be
  1039. X *    inhibited if desired, via the "r" flag.
  1040. X *
  1041. X *    The state stack is a linked list of states, with the new
  1042. X *    state added at the head.  This allows the stack to grow
  1043. X *    to the limits of memory if necessary.
  1044. X *
  1045. X */
  1046. X
  1047. XLOCAL VOID PushState ()
  1048. X{
  1049. X    REGISTER struct state *new;
  1050. X
  1051. X    new = (struct state *) DbugMalloc (sizeof (struct state));
  1052. X    new -> flags = 0;
  1053. X    new -> delay = 0;
  1054. X    new -> maxdepth = MAXDEPTH;
  1055. X    if (stack != NULL) {
  1056. X    new -> level = stack -> level;
  1057. X    } else {
  1058. X    new -> level = 0;
  1059. X    }
  1060. X    new -> out_file = stderr;
  1061. X    new -> functions = NULL;
  1062. X    new -> p_functions = NULL;
  1063. X    new -> keywords = NULL;
  1064. X    new -> processes = NULL;
  1065. X    new -> next_state = stack;
  1066. X    stack = new;
  1067. X    init_done = TRUE;
  1068. X}
  1069. X
  1070. X
  1071. X/*
  1072. X *  FUNCTION
  1073. X *
  1074. X *    DoTrace    check to see if tracing is current enabled
  1075. X *
  1076. X *  SYNOPSIS
  1077. X *
  1078. X *    LOCAL BOOLEAN DoTrace ()
  1079. X *
  1080. X *  DESCRIPTION
  1081. X *
  1082. X *    Checks to see if tracing is enabled based on whether the
  1083. X *    user has specified tracing, the maximum trace depth has
  1084. X *    not yet been reached, the current function is selected,
  1085. X *    and the current process is selected.  Returns TRUE if
  1086. X *    tracing is enabled, FALSE otherwise.
  1087. X *
  1088. X */
  1089. X
  1090. XLOCAL BOOLEAN DoTrace ()
  1091. X{
  1092. X    REGISTER BOOLEAN trace;
  1093. X
  1094. X    trace = FALSE;
  1095. X    if (TRACING) {
  1096. X    if (stack -> level <= stack -> maxdepth) {
  1097. X        if (InList (stack -> functions, func)) {
  1098. X        if (InList (stack -> processes, _db_process_)) {
  1099. X            trace = TRUE;
  1100. X        }
  1101. X        }
  1102. X    }
  1103. X    }
  1104. X    return (trace);
  1105. X}
  1106. X
  1107. X
  1108. X/*
  1109. X *  FUNCTION
  1110. X *
  1111. X *    DoProfile    check to see if profiling is current enabled
  1112. X *
  1113. X *  SYNOPSIS
  1114. X *
  1115. X *    LOCAL BOOLEAN DoProfile ()
  1116. X *
  1117. X *  DESCRIPTION
  1118. X *
  1119. X *    Checks to see if profiling is enabled based on whether the
  1120. X *    user has specified profiling, the maximum trace depth has
  1121. X *    not yet been reached, the current function is selected,
  1122. X *    and the current process is selected.  Returns TRUE if
  1123. X *    profiling is enabled, FALSE otherwise.
  1124. X *
  1125. X */
  1126. X
  1127. XLOCAL BOOLEAN DoProfile ()
  1128. X{
  1129. X    REGISTER BOOLEAN profile;
  1130. X
  1131. X    profile = FALSE;
  1132. X    if (PROFILING) {
  1133. X    if (stack -> level <= stack -> maxdepth) {
  1134. X        if (InList (stack -> p_functions, func)) {
  1135. X        if (InList (stack -> processes, _db_process_)) {
  1136. X            profile = TRUE;
  1137. X        }
  1138. X        }
  1139. X    }
  1140. X    }
  1141. X    return (profile);
  1142. X}
  1143. X
  1144. X
  1145. X/*
  1146. X *  FUNCTION
  1147. X *
  1148. X *    _db_keyword_    test keyword for member of keyword list
  1149. X *
  1150. X *  SYNOPSIS
  1151. X *
  1152. X *    BOOLEAN _db_keyword_ (keyword)
  1153. X *    char *keyword;
  1154. X *
  1155. X *  DESCRIPTION
  1156. X *
  1157. X *    Test a keyword to determine if it is in the currently active
  1158. X *    keyword list.  As with the function list, a keyword is accepted
  1159. X *    if the list is null, otherwise it must match one of the list
  1160. X *    members.  When debugging is not on, no keywords are accepted.
  1161. X *    After the maximum trace level is exceeded, no keywords are
  1162. X *    accepted (this behavior subject to change).  Additionally,
  1163. X *    the current function and process must be accepted based on
  1164. X *    their respective lists.
  1165. X *
  1166. X *    Returns TRUE if keyword accepted, FALSE otherwise.
  1167. X *
  1168. X */
  1169. X
  1170. XBOOLEAN _db_keyword_ (keyword)
  1171. Xchar *keyword;
  1172. X{
  1173. X    REGISTER BOOLEAN accept;
  1174. X
  1175. X    if (!init_done) {
  1176. X    _db_push_ ("");
  1177. X    }
  1178. X    accept = FALSE;
  1179. X    if (DEBUGGING) {
  1180. X    if (stack -> level <= stack -> maxdepth) {
  1181. X        if (InList (stack -> functions, func)) {
  1182. X        if (InList (stack -> keywords, keyword)) {
  1183. X            if (InList (stack -> processes, _db_process_)) {
  1184. X            accept = TRUE;
  1185. X            }
  1186. X        }
  1187. X        }
  1188. X    }
  1189. X    }
  1190. X    return (accept);
  1191. X}
  1192. X
  1193. X
  1194. X/*
  1195. X *  FUNCTION
  1196. X *
  1197. X *    Indent    indent a line to the given indentation level
  1198. X *
  1199. X *  SYNOPSIS
  1200. X *
  1201. X *    LOCAL VOID Indent (indent)
  1202. X *    int indent;
  1203. X *
  1204. X *  DESCRIPTION
  1205. X *
  1206. X *    Indent a line to the given level.  Note that this is
  1207. X *    a simple minded but portable implementation.
  1208. X *    There are better ways.
  1209. X *
  1210. X *    Also, the indent must be scaled by the compile time option
  1211. X *    of character positions per nesting level.
  1212. X *
  1213. X */
  1214. X
  1215. XLOCAL VOID Indent (indent)
  1216. Xint indent;
  1217. X{
  1218. X    REGISTER int count;
  1219. X    AUTO char buffer[PRINTBUF];
  1220. X
  1221. X    indent *= INDENT;
  1222. X    for (count = 0; (count < (indent - INDENT)) && (count < (PRINTBUF - 1)); count++) {
  1223. X    if ((count % INDENT) == 0) {
  1224. X        buffer[count] = '|';
  1225. X    } else {
  1226. X        buffer[count] = ' ';
  1227. X    }
  1228. X    }
  1229. X    buffer[count] = EOS;
  1230. X    (VOID) fprintf (_db_fp_, buffer);
  1231. X    (VOID) fflush (_db_fp_);
  1232. X}
  1233. X
  1234. X
  1235. X/*
  1236. X *  FUNCTION
  1237. X *
  1238. X *    FreeList    free all memory associated with a linked list
  1239. X *
  1240. X *  SYNOPSIS
  1241. X *
  1242. X *    LOCAL VOID FreeList (linkp)
  1243. X *    struct link *linkp;
  1244. X *
  1245. X *  DESCRIPTION
  1246. X *
  1247. X *    Given pointer to the head of a linked list, frees all
  1248. X *    memory held by the list and the members of the list.
  1249. X *
  1250. X */
  1251. X
  1252. XLOCAL VOID FreeList (linkp)
  1253. Xstruct link *linkp;
  1254. X{
  1255. X    REGISTER struct link *old;
  1256. X
  1257. X    while (linkp != NULL) {
  1258. X    old = linkp;
  1259. X    linkp = linkp -> next_link;
  1260. X    if (old -> string != NULL) {
  1261. X        free (old -> string);
  1262. X    }
  1263. X    free ((char *) old);
  1264. X    }
  1265. X}
  1266. X
  1267. X
  1268. X/*
  1269. X *  FUNCTION
  1270. X *
  1271. X *    StrDup   make a duplicate of a string in new memory
  1272. X *
  1273. X *  SYNOPSIS
  1274. X *
  1275. X *    LOCAL char *StrDup (string)
  1276. X *    char *string;
  1277. X *
  1278. X *  DESCRIPTION
  1279. X *
  1280. X *    Given pointer to a string, allocates sufficient memory to make
  1281. X *    a duplicate copy, and copies the string to the newly allocated
  1282. X *    memory.  Failure to allocated sufficient memory is immediately
  1283. X *    fatal.
  1284. X *
  1285. X */
  1286. X
  1287. X
  1288. XLOCAL char *StrDup (string)
  1289. Xchar *string;
  1290. X{
  1291. X    REGISTER char *new;
  1292. X
  1293. X    new = DbugMalloc (strlen (string) + 1);
  1294. X    (VOID) strcpy (new, string);
  1295. X    return (new);
  1296. X}
  1297. X
  1298. X
  1299. X/*
  1300. X *  FUNCTION
  1301. X *
  1302. X *    DoPrefix    print debugger line prefix prior to indentation
  1303. X *
  1304. X *  SYNOPSIS
  1305. X *
  1306. X *    LOCAL VOID DoPrefix (_line_)
  1307. X *    int _line_;
  1308. X *
  1309. X *  DESCRIPTION
  1310. X *
  1311. X *    Print prefix common to all debugger output lines, prior to
  1312. X *    doing indentation if necessary.  Print such information as
  1313. X *    current process name, current source file name and line number,
  1314. X *    and current function nesting depth.
  1315. X *
  1316. X */
  1317. X  
  1318. XLOCAL VOID DoPrefix (_line_)
  1319. Xint _line_;
  1320. X{
  1321. X    lineno++;
  1322. X    if (stack -> flags & NUMBER_ON) {
  1323. X    (VOID) fprintf (_db_fp_, "%5d: ", lineno);
  1324. X    }
  1325. X    if (stack -> flags & PROCESS_ON) {
  1326. X    (VOID) fprintf (_db_fp_, "%s: ", _db_process_);
  1327. X    }
  1328. X    if (stack -> flags & FILE_ON) {
  1329. X    (VOID) fprintf (_db_fp_, "%14s: ", file);
  1330. X    }
  1331. X    if (stack -> flags & LINE_ON) {
  1332. X    (VOID) fprintf (_db_fp_, "%5d: ", _line_);
  1333. X    }
  1334. X    if (stack -> flags & DEPTH_ON) {
  1335. X    (VOID) fprintf (_db_fp_, "%4d: ", stack -> level);
  1336. X    }
  1337. X    (VOID) fflush (_db_fp_);
  1338. X}
  1339. X
  1340. X
  1341. X/*
  1342. X *  FUNCTION
  1343. X *
  1344. X *    OpenFile    open new output stream for debugger output
  1345. X *
  1346. X *  SYNOPSIS
  1347. X *
  1348. X *    LOCAL VOID OpenFile (name)
  1349. X *    char *name;
  1350. X *
  1351. X *  DESCRIPTION
  1352. X *
  1353. X *    Given name of a new file (or "-" for stdout) opens the file
  1354. X *    and sets the output stream to the new file.
  1355. X *
  1356. X */
  1357. X
  1358. XLOCAL VOID OpenFile (name)
  1359. Xchar *name;
  1360. X{
  1361. X    REGISTER FILE *fp;
  1362. X    REGISTER BOOLEAN newfile;
  1363. X
  1364. X    if (name != NULL) {
  1365. X    if (strcmp (name, "-") == 0) {
  1366. X        _db_fp_ = stdout;
  1367. X        stack -> out_file = _db_fp_;
  1368. X    } else {
  1369. X        if (!Writable (name)) {
  1370. X        (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1371. X        perror ("");
  1372. X        (VOID) fflush (_db_fp_);
  1373. X        (VOID) XDelay (stack -> delay);
  1374. X        } else {
  1375. X        if (EXISTS (name)) {
  1376. X            newfile = FALSE;
  1377. X        } else {
  1378. X            newfile = TRUE;
  1379. X        }
  1380. X        fp = fopen (name, "a");
  1381. X        if (fp == NULL) {
  1382. X             (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1383. X            perror ("");
  1384. X            (VOID) fflush (_db_fp_);
  1385. X            (VOID) XDelay (stack -> delay);
  1386. X        } else {
  1387. X            _db_fp_ = fp;
  1388. X            stack -> out_file = fp;
  1389. X            if (newfile) {
  1390. X            ChangeOwner (name);
  1391. X            }
  1392. X        }
  1393. X        }
  1394. X    }
  1395. X    }
  1396. X}
  1397. X
  1398. X
  1399. X/*
  1400. X *  FUNCTION
  1401. X *
  1402. X *    OpenProfile    open new output stream for profiler output
  1403. X *
  1404. X *  SYNOPSIS
  1405. X *
  1406. X *    LOCAL VOID OpenProfile (name)
  1407. X *    char *name;
  1408. X *
  1409. X *  DESCRIPTION
  1410. X *
  1411. X *    Given name of a new file, opens the file
  1412. X *    and sets the profiler output stream to the new file.
  1413. X *
  1414. X *    It is currently unclear whether the prefered behavior is
  1415. X *    to truncate any existing file, or simply append to it.
  1416. X *    The latter behavior would be desirable for collecting
  1417. X *    accumulated runtime history over a number of separate
  1418. X *    runs.  It might take some changes to the analyzer program
  1419. X *    though, and the notes that Binayak sent with the profiling
  1420. X *    diffs indicated that append was the normal mode, but this
  1421. X *    does not appear to agree with the actual code. I haven't
  1422. X *    investigated at this time [fnf; 24-Jul-87].
  1423. X */
  1424. X
  1425. XLOCAL VOID OpenProfile (name)
  1426. Xchar *name;
  1427. X{
  1428. X    REGISTER FILE *fp;
  1429. X    REGISTER BOOLEAN newfile;
  1430. X
  1431. X    if (name != NULL) {
  1432. X    if (!Writable (name)) {
  1433. X        (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1434. X        perror ("");
  1435. X        (VOID) fflush (_db_fp_);
  1436. X        (VOID) XDelay (stack -> delay);
  1437. X    } else {
  1438. X        if (EXISTS (name)) {
  1439. X        newfile = FALSE;
  1440. X        } else {
  1441. X        newfile = TRUE;
  1442. X        }
  1443. X        fp = fopen (name, "w");
  1444. X        if (fp == NULL) {
  1445. X        (VOID) fprintf (_db_fp_, ERR_OPEN, _db_process_, name);
  1446. X        perror ("");
  1447. X        (VOID) fflush (_db_fp_);
  1448. X        (VOID) XDelay (stack -> delay);
  1449. X        } else {
  1450. X        _db_pfp_ = fp;
  1451. X        stack -> prof_file = fp;
  1452. X        if (newfile) {
  1453. X            ChangeOwner (name);
  1454. X        }
  1455. X        }
  1456. X    }
  1457. X    }
  1458. X}
  1459. X
  1460. X
  1461. X/*
  1462. X *  FUNCTION
  1463. X *
  1464. X *    CloseFile    close the debug output stream
  1465. X *
  1466. X *  SYNOPSIS
  1467. X *
  1468. X *    LOCAL VOID CloseFile (fp)
  1469. X *    FILE *fp;
  1470. X *
  1471. X *  DESCRIPTION
  1472. X *
  1473. X *    Closes the debug output stream unless it is standard output
  1474. X *    or standard error.
  1475. X *
  1476. X */
  1477. X
  1478. XLOCAL VOID CloseFile (fp)
  1479. XFILE *fp;
  1480. X{
  1481. X    if (fp != stderr && fp != stdout) {
  1482. X    if (fclose (fp) == EOF) {
  1483. X        (VOID) fprintf (stderr, ERR_CLOSE, _db_process_);
  1484. X        perror ("");
  1485. X        (VOID) fflush (stderr);
  1486. X        (VOID) XDelay (stack -> delay);
  1487. X    }
  1488. X    }
  1489. X}
  1490. X
  1491. X
  1492. X/*
  1493. X *  FUNCTION
  1494. X *
  1495. X *    DbugExit    print error message and exit
  1496. X *
  1497. X *  SYNOPSIS
  1498. X *
  1499. X *    LOCAL VOID DbugExit (why)
  1500. X *    char *why;
  1501. X *
  1502. X *  DESCRIPTION
  1503. X *
  1504. X *    Prints error message using current process name, the reason for
  1505. X *    aborting (typically out of memory), and exits with status 1.
  1506. X *    This should probably be changed to use a status code
  1507. X *    defined in the user's debugger include file.
  1508. X *
  1509. X */
  1510. XLOCAL VOID DbugExit (why)
  1511. Xchar *why;
  1512. X{
  1513. X    (VOID) fprintf (stderr, ERR_ABORT, _db_process_, why);
  1514. X    (VOID) fflush (stderr);
  1515. X    (VOID) XDelay (stack -> delay);
  1516. X    exit (1);
  1517. X}
  1518. X
  1519. X
  1520. X/*
  1521. X *  FUNCTION
  1522. X *
  1523. X *    DbugMalloc    allocate memory for debugger runtime support
  1524. X *
  1525. X *  SYNOPSIS
  1526. X *
  1527. X *    LOCAL char *DbugMalloc (size)
  1528. X *    int size;
  1529. X *
  1530. X *  DESCRIPTION
  1531. X *
  1532. X *    Allocate more memory for debugger runtime support functions.
  1533. X *    Failure to to allocate the requested number of bytes is
  1534. X *    immediately fatal to the current process.  This may be
  1535. X *    rather unfriendly behavior.  It might be better to simply
  1536. X *    print a warning message, freeze the current debugger state,
  1537. X *    and continue execution.
  1538. X *
  1539. X */
  1540. XLOCAL char *DbugMalloc (size)
  1541. Xint size;
  1542. X{
  1543. X    register char *new;
  1544. X
  1545. X    new = malloc ( size );
  1546. X    if (new == NULL) {
  1547. X    DbugExit ("out of memory");
  1548. X    }
  1549. X    return (new);
  1550. X}
  1551. X
  1552. X
  1553. X/*
  1554. X *    This function may be eliminated when strtok is available
  1555. X *    in the runtime environment (missing from BSD4.1).
  1556. X */
  1557. X
  1558. XLOCAL char *strtok (s1, s2)
  1559. Xchar *s1, *s2;
  1560. X{
  1561. X    static char *end = NULL;
  1562. X    REGISTER char *rtnval;
  1563. X
  1564. X    rtnval = NULL;
  1565. X    if (s2 != NULL) {
  1566. X    if (s1 != NULL) {
  1567. X        end = s1;
  1568. X        rtnval = strtok ((char *) NULL, s2);
  1569. X    } else if (end != NULL) {
  1570. X        if (*end != EOS) {
  1571. X        rtnval = end;
  1572. X        while (*end != *s2 && *end != EOS) {end++;}
  1573. X        if (*end != EOS) {
  1574. X            *end++ = EOS;
  1575. X        }
  1576. X        }
  1577. X    }
  1578. X    }
  1579. X    return (rtnval);
  1580. X}
  1581. X
  1582. X
  1583. X/*
  1584. X *  FUNCTION
  1585. X *
  1586. X *    BaseName    strip leading pathname components from name
  1587. X *
  1588. X *  SYNOPSIS
  1589. X *
  1590. X *    LOCAL char *BaseName (pathname)
  1591. X *    char *pathname;
  1592. X *
  1593. X *  DESCRIPTION
  1594. X *
  1595. X *    Given pointer to a complete pathname, locates the base file
  1596. X *    name at the end of the pathname and returns a pointer to
  1597. X *    it.
  1598. X *
  1599. X */
  1600. X
  1601. XLOCAL char *BaseName (pathname)
  1602. Xchar *pathname;
  1603. X{
  1604. X    register char *base;
  1605. X
  1606. X    base = strrchr (pathname, '/');
  1607. X    if (base++ == NULL) {
  1608. X    base = pathname;
  1609. X    }
  1610. X    return (base);
  1611. X}
  1612. X
  1613. X
  1614. X/*
  1615. X *  FUNCTION
  1616. X *
  1617. X *    Writable    test to see if a pathname is writable/creatable
  1618. X *
  1619. X *  SYNOPSIS
  1620. X *
  1621. X *    LOCAL BOOLEAN Writable (pathname)
  1622. X *    char *pathname;
  1623. X *
  1624. X *  DESCRIPTION
  1625. X *
  1626. X *    Because the debugger might be linked in with a program that
  1627. X *    runs with the set-uid-bit (suid) set, we have to be careful
  1628. X *    about opening a user named file for debug output.  This consists
  1629. X *    of checking the file for write access with the real user id,
  1630. X *    or checking the directory where the file will be created.
  1631. X *
  1632. X *    Returns TRUE if the user would normally be allowed write or
  1633. X *    create access to the named file.  Returns FALSE otherwise.
  1634. X *
  1635. X */
  1636. X
  1637. XLOCAL BOOLEAN Writable (pathname)
  1638. Xchar *pathname;
  1639. X{
  1640. X    REGISTER BOOLEAN granted;
  1641. X#ifdef unix
  1642. X    REGISTER char *lastslash;
  1643. X#endif
  1644. X
  1645. X#ifndef unix
  1646. X    granted = TRUE;
  1647. X#else
  1648. X    granted = FALSE;
  1649. X    if (EXISTS (pathname)) {
  1650. X    if (WRITABLE (pathname)) {
  1651. X        granted = TRUE;
  1652. X    }
  1653. X    } else {
  1654. X    lastslash = strrchr (pathname, '/');
  1655. X    if (lastslash != NULL) {
  1656. X        *lastslash = EOS;
  1657. X    } else {
  1658. X        pathname = ".";
  1659. X    }
  1660. X    if (WRITABLE (pathname)) {
  1661. X        granted = TRUE;
  1662. X    }
  1663. X    if (lastslash != NULL) {
  1664. X        *lastslash = '/';
  1665. X    }
  1666. X    }
  1667. X#endif
  1668. X    return (granted);
  1669. X}
  1670. X
  1671. X
  1672. X/*
  1673. X *    This function may be eliminated when strrchr is available
  1674. X *    in the runtime environment (missing from BSD4.1).
  1675. X *    Alternately, you can use rindex() on BSD systems.
  1676. X */
  1677. X
  1678. XLOCAL char *strrchr (s, c)
  1679. Xchar *s;
  1680. Xchar c;
  1681. X{
  1682. X    REGISTER char *scan;
  1683. X
  1684. X    for (scan = s; *scan != EOS; scan++) {;}
  1685. X    while (scan > s && *--scan != c) {;}
  1686. X    if (*scan != c) {
  1687. X    scan = NULL;
  1688. X    }
  1689. X    return (scan);
  1690. X}
  1691. X
  1692. X
  1693. X/*
  1694. X *  FUNCTION
  1695. X *
  1696. X *    ChangeOwner    change owner to real user for suid programs
  1697. X *
  1698. X *  SYNOPSIS
  1699. X *
  1700. X *    LOCAL VOID ChangeOwner (pathname)
  1701. X *
  1702. X *  DESCRIPTION
  1703. X *
  1704. X *    For unix systems, change the owner of the newly created debug
  1705. X *    file to the real owner.  This is strictly for the benefit of
  1706. X *    programs that are running with the set-user-id bit set.
  1707. X *
  1708. X *    Note that at this point, the fact that pathname represents
  1709. X *    a newly created file has already been established.  If the
  1710. X *    program that the debugger is linked to is not running with
  1711. X *    the suid bit set, then this operation is redundant (but
  1712. X *    harmless).
  1713. X *
  1714. X */
  1715. X
  1716. XLOCAL VOID ChangeOwner (pathname)
  1717. Xchar *pathname;
  1718. X{
  1719. X#ifdef unix
  1720. X    if (chown (pathname, getuid (), getgid ()) == -1) {
  1721. X    (VOID) fprintf (stderr, ERR_CHOWN, _db_process_, pathname);
  1722. X    perror ("");
  1723. X    (VOID) fflush (stderr);
  1724. X    (VOID) XDelay (stack -> delay);
  1725. X    }
  1726. X#endif
  1727. X}
  1728. X
  1729. X
  1730. X/*
  1731. X *  FUNCTION
  1732. X *
  1733. X *    _db_setjmp_    save debugger environment
  1734. X *
  1735. X *  SYNOPSIS
  1736. X *
  1737. X *    VOID _db_setjmp_ ()
  1738. X *
  1739. X *  DESCRIPTION
  1740. X *
  1741. X *    Invoked as part of the user's DBUG_SETJMP macro to save
  1742. X *    the debugger environment in parallel with saving the user's
  1743. X *    environment.
  1744. X *
  1745. X */
  1746. X
  1747. XVOID _db_setjmp_ ()
  1748. X{
  1749. X   jmplevel = stack -> level;
  1750. X   jmpfunc = func;
  1751. X   jmpfile = file;
  1752. X}
  1753. X
  1754. X
  1755. X/*
  1756. X *  FUNCTION
  1757. X *
  1758. X *    _db_longjmp_    restore previously saved debugger environment
  1759. X *
  1760. X *  SYNOPSIS
  1761. X *
  1762. X *    VOID _db_longjmp_ ()
  1763. X *
  1764. X *  DESCRIPTION
  1765. X *
  1766. X *    Invoked as part of the user's DBUG_LONGJMP macro to restore
  1767. X *    the debugger environment in parallel with restoring the user's
  1768. X *    previously saved environment.
  1769. X *
  1770. X */
  1771. X
  1772. XVOID _db_longjmp_ ()
  1773. X{
  1774. X    stack -> level = jmplevel;
  1775. X    if (jmpfunc) {
  1776. X    func = jmpfunc;
  1777. X    }
  1778. X    if (jmpfile) {
  1779. X    file = jmpfile;
  1780. X    }
  1781. X}
  1782. X
  1783. X
  1784. X/*
  1785. X *  FUNCTION
  1786. X *
  1787. X *    DelayArg   convert D flag argument to appropriate value
  1788. X *
  1789. X *  SYNOPSIS
  1790. X *
  1791. X *    LOCAL int DelayArg (value)
  1792. X *    int value;
  1793. X *
  1794. X *  DESCRIPTION
  1795. X *
  1796. X *    Converts delay argument, given in tenths of a second, to the
  1797. X *    appropriate numerical argument used by the system to delay
  1798. X *    that that many tenths of a second.  For example, on the
  1799. X *    AMIGA, there is a system call "Delay()" which takes an
  1800. X *    argument in ticks (50 per second).  On unix, the sleep
  1801. X *    command takes seconds.  Thus a value of "10", for one
  1802. X *    second of delay, gets converted to 50 on the amiga, and 1
  1803. X *    on unix.  Other systems will need to use a timing loop.
  1804. X *
  1805. X */
  1806. X
  1807. XLOCAL int DelayArg (value)
  1808. Xint value;
  1809. X{
  1810. X    int delayarg = 0;
  1811. X    
  1812. X#ifdef unix
  1813. X    delayarg = value / 10;        /* Delay is in seconds for sleep () */
  1814. X#endif
  1815. X#ifdef AMIGA
  1816. X    delayarg = (HZ * value) / 10;    /* Delay in ticks for XDelay () */
  1817. X#endif
  1818. X    return (delayarg);
  1819. X}
  1820. X
  1821. X
  1822. X/*
  1823. X *    A dummy delay stub for systems that do not support delays.
  1824. X *    With a little work, this can be turned into a timing loop.
  1825. X */
  1826. X
  1827. X#ifndef unix
  1828. X#ifndef AMIGA
  1829. XXDelay ()
  1830. X{
  1831. X}
  1832. X#endif
  1833. X#endif
  1834. X
  1835. X
  1836. X/*
  1837. X *  FUNCTION
  1838. X *
  1839. X *    perror    perror simulation for systems that don't have it
  1840. X *
  1841. X *  SYNOPSIS
  1842. X *
  1843. X *    LOCAL VOID perror (s)
  1844. X *    char *s;
  1845. X *
  1846. X *  DESCRIPTION
  1847. X *
  1848. X *    Perror produces a message on the standard error stream which
  1849. X *    provides more information about the library or system error
  1850. X *    just encountered.  The argument string s is printed, followed
  1851. X *    by a ':', a blank, and then a message and a newline.
  1852. X *
  1853. X *    An undocumented feature of the unix perror is that if the string
  1854. X *    's' is a null string (NOT a NULL pointer!), then the ':' and
  1855. X *    blank are not printed.
  1856. X *
  1857. X *    This version just complains about an "unknown system error".
  1858. X *
  1859. X */
  1860. X
  1861. X#if !unix && !(AMIGA || LATTICE || __TURBOC__ )
  1862. XLOCAL VOID perror (s)
  1863. X#if __STDC__
  1864. Xconst char *s;
  1865. X#else
  1866. Xchar *s;
  1867. X#endif
  1868. X{
  1869. X    if (s && *s != EOS) {
  1870. X    (VOID) fprintf (stderr, "%s: ", s);
  1871. X    }
  1872. X    (VOID) fprintf (stderr, "<unknown system error>\n");
  1873. X}
  1874. X#endif    /* !unix && !(AMIGA && LATTICE) */
  1875. X
  1876. X/*
  1877. X * Here we need the definitions of the clock routine.  Add your
  1878. X * own for whatever system that you have.
  1879. X */
  1880. X
  1881. X#if unix
  1882. X
  1883. X# include <sys/param.h>
  1884. X# if BSD4_3 || sun
  1885. X
  1886. X/*
  1887. X * Definition of the Clock() routine for 4.3 BSD.
  1888. X */
  1889. X
  1890. X#include <sys/time.h>
  1891. X#include <sys/resource.h>
  1892. X
  1893. X/*
  1894. X * Returns the user time in milliseconds used by this process so
  1895. X * far.
  1896. X */
  1897. X
  1898. XLOCAL unsigned long Clock ()
  1899. X{
  1900. X    struct rusage ru;
  1901. X
  1902. X    (VOID) getrusage (RUSAGE_SELF, &ru);
  1903. X    return ((ru.ru_utime.tv_sec * 1000) + (ru.ru_utime.tv_usec / 1000));
  1904. X}
  1905. X
  1906. X#else
  1907. X
  1908. XLOCAL unsigned long Clock ()
  1909. X{
  1910. X    return (0);
  1911. X}
  1912. X
  1913. X# endif
  1914. X
  1915. X#else
  1916. X
  1917. X#if AMIGA
  1918. X
  1919. Xstruct DateStamp {        /* Yes, this is a hack, but doing it right */
  1920. X    long ds_Days;        /* is incredibly ugly without splitting this */
  1921. X    long ds_Minute;        /* off into a separate file */
  1922. X    long ds_Tick;
  1923. X};
  1924. X
  1925. Xstatic int first_clock = TRUE;
  1926. Xstatic struct DateStamp begin;
  1927. Xstatic struct DateStamp elapsed;
  1928. X
  1929. XLOCAL unsigned long Clock ()
  1930. X{
  1931. X    register struct DateStamp *now;
  1932. X    register unsigned long millisec = 0;
  1933. X    extern VOID *AllocMem ();
  1934. X
  1935. X    now = (struct DateStamp *) AllocMem ((long) sizeof (struct DateStamp), 0L);
  1936. X    if (now != NULL) {
  1937. X    if (first_clock == TRUE) {
  1938. X        first_clock = FALSE;
  1939. X        (VOID) DateStamp (now);
  1940. X        begin = *now;
  1941. X    }
  1942. X    (VOID) DateStamp (now);
  1943. X    millisec = 24 * 3600 * (1000 / HZ) * (now -> ds_Days - begin.ds_Days);
  1944. X    millisec += 60 * (1000 / HZ) * (now -> ds_Minute - begin.ds_Minute);
  1945. X    millisec += (1000 / HZ) * (now -> ds_Tick - begin.ds_Tick);
  1946. X    (VOID) FreeMem (now, (long) sizeof (struct DateStamp));
  1947. X    }
  1948. X    return (millisec);
  1949. X}
  1950. X
  1951. X#else
  1952. X
  1953. XLOCAL unsigned long Clock ()
  1954. X{
  1955. X    return (0);
  1956. X}
  1957. X
  1958. X#endif    /* AMIGA */
  1959. X
  1960. X#endif    /* unix */
  1961. X
  1962. X#ifdef AMIGA
  1963. XXDelay(x)
  1964. Xint x;
  1965. X{
  1966. X    if (x) Delay(x);    /* fix Delay bug in AmigaDOS */
  1967. X}
  1968. X#endif
  1969. X
  1970. END_OF_FILE
  1971.   if test 44504 -ne `wc -c <'dbug/dbug.c'`; then
  1972.     echo shar: \"'dbug/dbug.c'\" unpacked with wrong size!
  1973.   fi
  1974.   # end of 'dbug/dbug.c'
  1975. fi
  1976. if test -f 'dbug/dbug.qr' -a "${1}" != "-c" ; then 
  1977.   echo shar: Will not clobber existing file \"'dbug/dbug.qr'\"
  1978. else
  1979.   echo shar: Extracting \"'dbug/dbug.qr'\" \(2232 characters\)
  1980.   sed "s/^X//" >'dbug/dbug.qr' <<'END_OF_FILE'
  1981. X.\"    Quick reference list for the DBUG package, from dbug.p, pp 15-19
  1982. X.\"    First group is of interest to programmers, second to users.
  1983. X.\"
  1984. X.pl 1
  1985. X.ll 80
  1986. X.lt 80
  1987. X
  1988. X.ti -5
  1989. X\fBDBUG_OFF\fP
  1990. X.br
  1991. Xif defined during compilation, removes all debugging from the program
  1992. X
  1993. X.ti -5
  1994. X\fBDBUG_ENTER\fP(char *\fIfname\fP)
  1995. X.br
  1996. Xmarks entry to the function \fIfname\fP
  1997. X
  1998. X.ti -5
  1999. X\fBDBUG_RETURN\fP(int \fIvalue\fP)
  2000. X.ti -5
  2001. X\fBDBUG_VOID_RETURN\fP
  2002. X.br
  2003. Xmarks the return from the current function
  2004. X
  2005. X.ti -5
  2006. X\fBDBUG_PROCESS\fP(char *\fIpname\fP)
  2007. X.br
  2008. Xmarks the beginning of the process \fIpname\fP
  2009. X
  2010. X.ti -5
  2011. X\fBDBUG_PUSH\fP(char *\fIstate\fP)
  2012. X.br
  2013. Xsets up a new debugging state (see \fIDebugging States\fP below)
  2014. X
  2015. X.ti -5
  2016. X\fBDBUG_POP\fP(void)
  2017. X.br
  2018. Xrestores the previous debugging state
  2019. X
  2020. X.ti -5
  2021. X\fBDBUG_FILE\fP
  2022. X.br
  2023. Xa file pointer which may be used to add output to the debugging trace
  2024. X
  2025. X.ti -5
  2026. X\fBDBUG_EXECUTE\fP(char *\fIkey\fP, \fIC_code\fP)
  2027. X.br
  2028. Xif debugging is active for \fIkey\fP, executes the \fIC_code\fP
  2029. X
  2030. X.ti -5
  2031. X\fBDBUG_PRINT\fP(char *\fIformat\fP, \fIarg ...\fP)
  2032. X.br
  2033. Xif debugging is active for \fIkey\fP,
  2034. Xexecutes \fBfprintf\fP to \fBDBUG_FILE\fP
  2035. Xusing the \fIformat\fP and \fIarg\fPs specified
  2036. X
  2037. X.ti -5
  2038. X\fBDBUG_SETJMP\fP(\fIsetjmp_args\fP)
  2039. X.ti -5
  2040. X\fBDBUG_LONGJMP\fP(\fIlongjmp_args\fP)
  2041. X.br
  2042. Xreplace \fBsetjmp\fP() and \fBlongjmp\fP(),
  2043. Xallowing the debugging state to be restored properly
  2044. X
  2045. X
  2046. X
  2047. X.ti -5
  2048. X\fBd\fP[,\fIkey\fP...]
  2049. X.br
  2050. Xenable debugging for the \fIkey\fPs specified
  2051. X
  2052. X.ti -5
  2053. X\fBF\fP[,\fItime\fP]
  2054. X.br
  2055. Xdelay for \fItime\fP tenths of a second after each output
  2056. X
  2057. X.ti -5
  2058. X\fBf\fP[,\fIfunction\fP ...]
  2059. X.br
  2060. Xlimit debugging to the specified \fIfunction\fPs
  2061. X
  2062. X.ti -5
  2063. X\fBF\fP    mark debugger output with the source file name
  2064. X
  2065. X.ti -5
  2066. X\fBL\fP    mark debugger output with the source file line number
  2067. X
  2068. X.ti -5
  2069. X\fBn\fP    mark debugger output with the function nesting depth
  2070. X
  2071. X.ti -5
  2072. X\fBN\fP    number debugger output lines sequentially
  2073. X
  2074. X.ti -5
  2075. X\fBo\fP[,\fIfile\fP]
  2076. X.br
  2077. Xwrite debugger output to \fIfile\fP
  2078. X
  2079. X.ti -5
  2080. X\fBp\fP[,\fIprocesses\fP ...]
  2081. X.br
  2082. Xlimit debugging to the specified \fIprocess\fPes
  2083. X
  2084. X.ti -5
  2085. X\fBP\fP    mark debugger output with the process name
  2086. X
  2087. X.ti -5
  2088. X\fBr\fP    reset indentation level to zero
  2089. X
  2090. X.ti -5
  2091. X\fBt\fP[,N]
  2092. X.br
  2093. Xenable function control flow tracing
  2094. Xto a maximum depth of \fIN\fP
  2095. END_OF_FILE
  2096.   if test 2232 -ne `wc -c <'dbug/dbug.qr'`; then
  2097.     echo shar: \"'dbug/dbug.qr'\" unpacked with wrong size!
  2098.   fi
  2099.   # end of 'dbug/dbug.qr'
  2100. fi
  2101. if test ! -d 'doc' ; then
  2102.     echo shar: Creating directory \"'doc'\"
  2103.     mkdir 'doc'
  2104. fi
  2105. if test ! -d 'examples' ; then
  2106.     echo shar: Creating directory \"'examples'\"
  2107.     mkdir 'examples'
  2108. fi
  2109. if test -f 'oracle.mus' -a "${1}" != "-c" ; then 
  2110.   echo shar: Will not clobber existing file \"'oracle.mus'\"
  2111. else
  2112.   echo shar: Extracting \"'oracle.mus'\" \(11035 characters\)
  2113.   sed "s/^X//" >'oracle.mus' <<'END_OF_FILE'
  2114. X/* oracle.mus
  2115. X *
  2116. X * User subroutine interface to Oracle functions
  2117. X *
  2118. X * NOTE: Do not modify oracle.c as it is created automagically from oracle.mus.
  2119. X *     Modify oracle.mus instead, or your changes will be lost.
  2120. X */
  2121. X/* Copyright 1991, 1992 Kevin Stock.
  2122. X *
  2123. X * You may copy this under the terms of the GNU General Public License,
  2124. X * or the Artistic License, copies of which should have accompanied your
  2125. X * Perl kit.
  2126. X */
  2127. X
  2128. X#include <ctype.h>
  2129. X
  2130. X#include "EXTERN.h"
  2131. X#include "perl.h"
  2132. X#include "orafns.h"
  2133. X#include "patchlevel.h"
  2134. X
  2135. X
  2136. Xstatic enum uservars {
  2137. X    UV_ora_cache,
  2138. X    UV_ora_debug,
  2139. X    UV_ora_errno,
  2140. X    UV_ora_errstr,
  2141. X    UV_ora_long,
  2142. X    UV_ora_trunc,
  2143. X    UV_ora_verno,
  2144. X};
  2145. X
  2146. Xstatic enum usersubs {
  2147. X    US_ora_version,
  2148. X    US_ora_login,
  2149. X    US_ora_open,
  2150. X    US_ora_titles,
  2151. X    US_ora_lengths,
  2152. X    US_ora_types,
  2153. X    US_ora_bind,
  2154. X    US_ora_fetch,
  2155. X    US_ora_close,
  2156. X    US_ora_do,
  2157. X    US_ora_logoff,
  2158. X    US_ora_commit,
  2159. X    US_ora_rollback,
  2160. X    US_ora_autocommit,
  2161. X};
  2162. X
  2163. Xstatic int usersub();
  2164. Xstatic int userset();
  2165. Xstatic int userval();
  2166. X
  2167. Xint
  2168. Xinit_oracle()
  2169. X{
  2170. X    struct ufuncs uf;
  2171. X    char *filename = "oracle.c";
  2172. X
  2173. X    uf.uf_set = userset;
  2174. X    uf.uf_val = userval;
  2175. X
  2176. X#define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
  2177. X
  2178. X    MAGICVAR("ora_cache",    UV_ora_cache);
  2179. X    MAGICVAR("ora_debug",    UV_ora_debug);
  2180. X    MAGICVAR("ora_errno",    UV_ora_errno);
  2181. X    MAGICVAR("ora_errstr",    UV_ora_errstr);
  2182. X    MAGICVAR("ora_trunc",    UV_ora_trunc);
  2183. X    MAGICVAR("ora_long",    UV_ora_long);
  2184. X    MAGICVAR("ora_verno",    UV_ora_verno);
  2185. X
  2186. X    make_usub("ora_version",    US_ora_version,        usersub, filename);
  2187. X    make_usub("ora_login",    US_ora_login,        usersub, filename);
  2188. X    make_usub("ora_open",    US_ora_open,        usersub, filename);
  2189. X    make_usub("ora_titles",    US_ora_titles,        usersub, filename);
  2190. X    make_usub("ora_lengths",    US_ora_lengths,        usersub, filename);
  2191. X    make_usub("ora_types",    US_ora_types,        usersub, filename);
  2192. X    make_usub("ora_bind",    US_ora_bind,        usersub, filename);
  2193. X    make_usub("ora_fetch",    US_ora_fetch,        usersub, filename);
  2194. X    make_usub("ora_close",    US_ora_close,        usersub, filename);
  2195. X    make_usub("ora_do",        US_ora_do,        usersub, filename);
  2196. X    make_usub("ora_logoff",    US_ora_logoff,        usersub, filename);
  2197. X    make_usub("ora_commit",    US_ora_commit,        usersub, filename);
  2198. X    make_usub("ora_rollback",    US_ora_rollback,    usersub, filename);
  2199. X    make_usub("ora_autocommit",    US_ora_autocommit,  usersub, filename);
  2200. X};
  2201. X
  2202. X
  2203. Xstatic int
  2204. Xusersub(ix, sp, items)
  2205. Xint ix;
  2206. Xregister int sp;
  2207. Xregister int items;
  2208. X{
  2209. X    STR **st = stack->ary_array + sp;
  2210. X    register int i;
  2211. X    register char *tmps;
  2212. X    register STR *Str;        /* used in str_get and str_gnum macros */
  2213. X
  2214. X    switch (ix) {
  2215. X
  2216. XCASE    void    ora_version
  2217. XEND
  2218. X
  2219. XCASE    char *    ora_login
  2220. XI    char *    database
  2221. XI    char *    name
  2222. XI    char *    password
  2223. XEND
  2224. X
  2225. X    case US_ora_open:
  2226. X    if ((items < 2) || (items > 3))
  2227. X        fatal("Usage: &ora_open($lda, $stmt [, $cache])");
  2228. X    else {
  2229. X        char * retval;
  2230. X        char * lda              = (char *) str_get(st[1]);
  2231. X        char * stmt              = (char *) str_get(st[2]);
  2232. X        int     cache = (items == 2) ?    ora_cache
  2233. X                      : (int)     str_gnum(st[3]);
  2234. X
  2235. X        retval = ora_open(lda, stmt, cache);
  2236. X        str_set(st[0], (char*) retval);
  2237. X    }
  2238. X    return sp;
  2239. X
  2240. X    case US_ora_titles:
  2241. X    if (items != 1) {
  2242. X        fatal("Usage: @array = &ora_titles($csr)");
  2243. X    } else {
  2244. X        char *csr              = (char *) str_get(st[1]);
  2245. X        int  retval;
  2246. X
  2247. X        retval = ora_titles(csr);
  2248. X        astore(stack, sp + retval, Nullstr);
  2249. X        st = stack->ary_array + sp;
  2250. X        for (i = 0 ; i < retval ; i++) {
  2251. X        tmps = ora_result[i];
  2252. X        st[i] = str_2mortal(str_make(tmps, strlen(tmps)));
  2253. X        }
  2254. X        return sp + retval - 1;
  2255. X    }
  2256. X    /* NOTREACHED */
  2257. X
  2258. X    case US_ora_lengths:
  2259. X    if (items != 1) {
  2260. X        fatal("Usage: @array = &ora_lengths($csr)");
  2261. X    } else {
  2262. X        char *csr              = (char *) str_get(st[1]);
  2263. X        int  retval, length;
  2264. X
  2265. X        retval = ora_lengths(csr);
  2266. X        astore(stack, sp + retval, Nullstr);
  2267. X        st = stack->ary_array + sp;
  2268. X        for (i = 0 ; i < retval ; i++) {
  2269. X            length = atoi(ora_result[i]);
  2270. X            st[i] = str_2mortal(str_make("", 0));
  2271. X            str_numset(st[i], (double) length);
  2272. X        }
  2273. X        return sp + retval - 1;
  2274. X    }
  2275. X    /* NOTREACHED */
  2276. X
  2277. X    case US_ora_types:
  2278. X    if (items != 1) {
  2279. X        fatal("Usage: @array = &ora_types($csr)");
  2280. X    } else {
  2281. X        char *csr              = (char *) str_get(st[1]);
  2282. X        int  retval, type;
  2283. X
  2284. X        retval = ora_types(csr);
  2285. X        astore(stack, sp + retval, Nullstr);
  2286. X        st = stack->ary_array + sp;
  2287. X        for (i = 0 ; i < retval ; i++) {
  2288. X            type = atoi(ora_result[i]);
  2289. X            st[i] = str_2mortal(str_make("", 0));
  2290. X            str_numset(st[i], (double) type);
  2291. X        }
  2292. X        return sp + retval - 1;
  2293. X    }
  2294. X    /* NOTREACHED */
  2295. X
  2296. X    case US_ora_fetch:
  2297. X    if ((items < 1) || (items > 2)) {
  2298. X        if (curcsv->wantarray)
  2299. X            fatal("Usage: @array = &ora_fetch($csr[, $trunc])");
  2300. X        else
  2301. X            fatal("Usage: $nfields = &ora_fetch($csr)");
  2302. X    } else {
  2303. X        char *csr              = (char *) str_get(st[1]);
  2304. X        int     trunc = (items == 2) ? (int)     str_gnum(st[2])
  2305. X                      : ora_trunc;
  2306. X
  2307. X        if (curcsv->wantarray) {    /* in array context, return the data */
  2308. X        int  retval;
  2309. X
  2310. X        retval = ora_fetch(csr, trunc);
  2311. X        astore(stack, sp + retval, Nullstr);
  2312. X        st = stack->ary_array + sp;
  2313. X        for (i = 0 ; i < retval ; i++) {
  2314. X            tmps = ora_result[i];
  2315. X            st[i] = str_2mortal(str_make(tmps, strlen(tmps)));
  2316. X        }
  2317. X        return sp + retval - 1;
  2318. X        } else {    /* in scalar context, return the number of fields */
  2319. X        struct cursor *csrp;
  2320. X        extern int check_csr();
  2321. X
  2322. X        csrp = (struct cursor *) strtoul(csr, (char *) NULL, 0);
  2323. X        if (check_csr(csrp))
  2324. X            str_numset(st[0], (double) csrp->nfields);
  2325. X        else
  2326. X            str_set(st[0], (char *) NULL);
  2327. X        return sp;
  2328. X        }
  2329. X    }
  2330. X    /* NOTREACHED */
  2331. X
  2332. X    case US_ora_bind:
  2333. X    if (items < 2)
  2334. X        fatal("Usage: &ora_bind($csr, $var ...)");
  2335. X    else {
  2336. X        char *csr        = (char *) str_get(st[1]);
  2337. X        char **vars        = (char **) malloc((items-1) * sizeof(char *));
  2338. X        int retval;
  2339. X
  2340. X        if (vars == NULL)
  2341. X        {
  2342. X        ora_errno = ORAP_NOMEM;
  2343. X        retval = 0;
  2344. X        }
  2345. X        else
  2346. X        {
  2347. X        for (i = 0 ; i < items - 1 ; i++)
  2348. X        {
  2349. X            vars[i] = (char *) str_get(st[i+2]);
  2350. X        }
  2351. X        retval = ora_bind(csr, vars, items - 1);
  2352. X        free(vars);
  2353. X        }
  2354. X
  2355. X        str_numset(st[0], (double) retval);
  2356. X    }
  2357. X    return sp;
  2358. X
  2359. XCASE    char *    ora_do
  2360. XI    char *    lda
  2361. XI    char *    stmt
  2362. XEND
  2363. X
  2364. XCASE    char *    ora_close
  2365. XI    char *    csr
  2366. XEND
  2367. X
  2368. XCASE    char *    ora_logoff
  2369. XI    char *    lda
  2370. XEND
  2371. X
  2372. XCASE    char *    ora_commit
  2373. XI    char *    lda
  2374. XEND  
  2375. X
  2376. XCASE    char *    ora_rollback
  2377. XI    char *    lda
  2378. XEND
  2379. X
  2380. XCASE    char *    ora_autocommit
  2381. XI    char *    lda
  2382. XI    int    on_off
  2383. XEND
  2384. X
  2385. X    default:
  2386. X    fatal("Unimplemented user-defined subroutine");
  2387. X    }
  2388. X    return sp;
  2389. X}
  2390. X
  2391. Xstatic int
  2392. Xuserset(ix, str)
  2393. Xint ix;
  2394. XSTR *str;
  2395. X{
  2396. X    int n;
  2397. X#ifdef    DEBUGGING
  2398. X    register char *s;
  2399. X#endif
  2400. X
  2401. X    switch (ix) {
  2402. X
  2403. X    case UV_ora_long:
  2404. X    if ((n = (int) str_gnum(str)) <= 0)
  2405. X        warn("Cannot set a negative or zero LONG size");
  2406. X    else
  2407. X        ora_long = n;
  2408. X    DBUG_PRINT("info", ("ora_long set to %d", ora_long));
  2409. X    break;
  2410. X
  2411. X    case UV_ora_trunc:
  2412. X    if (n = (int) str_gnum(str))
  2413. X        ora_trunc = 1;
  2414. X    else
  2415. X        ora_trunc = 0;
  2416. X    DBUG_PRINT("info", ("ora_trunc set to %d", ora_trunc));
  2417. X    break;
  2418. X
  2419. X    case UV_ora_cache:
  2420. X    if ((n = (int) str_gnum(str)) < 0)
  2421. X        warn("Cannot set a negative cache size!");
  2422. X    else if (n == 0)
  2423. X        ora_cache = CACHE_SIZE;        /* restore default value */
  2424. X    else
  2425. X        ora_cache = n;
  2426. X    DBUG_PRINT("info", ("ora_cache set to %d", ora_cache));
  2427. X    break;
  2428. X
  2429. X    case UV_ora_debug:
  2430. X
  2431. X#ifdef    DEBUGGING
  2432. X
  2433. X    /* An assignment to ora_debug pops off the old debugging state and
  2434. X     * pushes the new one converting from numeric to string debugging
  2435. X     * if necessary. Nested debugging is not supported.
  2436. X     *
  2437. X     * However, there is an interesting dilemma:
  2438. X     *   What form of debugging should be in force during the assignment?
  2439. X     *
  2440. X     * The choices are:
  2441. X     *   1  The old debugging state before the assignment
  2442. X     *   2  No debugging
  2443. X     *   3  An mixture of the old and new debugging states.
  2444. X     *
  2445. X     * I have chosen [1], on the following basis:
  2446. X     *   Any debugging is better than none
  2447. X     *   Consistent debugging is better than mixed
  2448. X     *   DBUG_POP doesn't mind if the stack is empty
  2449. X     * but I would be grateful for any comments concerning this.
  2450. X     */
  2451. X
  2452. X    if ((*(s = str_get(str)) == '-') && (s[1] == '#'))
  2453. X    {
  2454. X        /* skip over -# so that it can be used as a flag */
  2455. X        s += 2;
  2456. X    }
  2457. X
  2458. X    if (ora_debug != NULL)
  2459. X    {
  2460. X        DBUG_PRINT("free", ("freeing ora_debug (%lx)",(long)ora_debug));
  2461. X        free(ora_debug);
  2462. X    }
  2463. X
  2464. X    if (*s == '\0')
  2465. X    {
  2466. X        ora_debug = NULL;
  2467. X    }
  2468. X    else
  2469. X    {
  2470. X        if (isdigit(*s))
  2471. X        {
  2472. X            /* numeric value, convert it to something usable */
  2473. X            s = convert_debug(atoi(s));
  2474. X        }
  2475. X
  2476. X        if ((ora_debug = malloc(strlen(s) + 1)) == NULL)
  2477. X        {
  2478. X            DBUG_PRINT("malloc",
  2479. X                ("no memory (%d bytes) for ora_debug",
  2480. X                strlen(s) + 1));
  2481. X            warn("cannot set ora_debug: out of memory");
  2482. X        }
  2483. X        else
  2484. X        {
  2485. X            DBUG_PRINT("malloc", ("got ora_debug %d bytes at %lx",
  2486. X                strlen(s) + 1, (long) ora_debug));
  2487. X            strcpy(ora_debug, s);
  2488. X        }
  2489. X    }
  2490. X
  2491. X    DBUG_POP();            /* remove the previous state, if any */
  2492. X    if (ora_debug != NULL)
  2493. X    {
  2494. X        DBUG_PUSH(ora_debug);    /* set up the new state             */
  2495. X        DBUG_PRINT("info", ("ora_debug set to %s", ora_debug));
  2496. X    }
  2497. X    else
  2498. X    {
  2499. X        DBUG_PRINT("info", ("ora_debug set to NULL"));
  2500. X    }
  2501. X#else
  2502. X    if (warn_on_debug)
  2503. X    {
  2504. X        warn("oraperl debugging not available");
  2505. X        warn_on_debug = 0;    /* so we only get one warning */
  2506. X    }
  2507. X#endif
  2508. X
  2509. X    break;
  2510. X
  2511. X    case UV_ora_errno:
  2512. X    fatal("ora_errno is read-only");
  2513. X    break;
  2514. X
  2515. X    case UV_ora_errstr:
  2516. X    fatal("ora_errstr is read-only");
  2517. X    break;
  2518. X
  2519. X    case UV_ora_verno:
  2520. X    fatal("ora_verno is read-only");
  2521. X    break;
  2522. X    }
  2523. X    return 0;
  2524. X}
  2525. X
  2526. X
  2527. X/* ora_errlist[] contains error messages corresponding to Oraperl's own
  2528. X * error codes. These do not include Oracle errors.
  2529. X */
  2530. X
  2531. Xchar *ora_errlist[] =
  2532. X{
  2533. X    "",    /* not used */
  2534. X    "insufficient memory",
  2535. X    "invalid cursor",
  2536. X    "invalid login data area",
  2537. X    "couldn't set ORACLE_SID",
  2538. X    "bad colon variable sequence",
  2539. X    "wrong number of variables",
  2540. X    "statement does not return data",
  2541. X};
  2542. X
  2543. X
  2544. Xstatic int
  2545. Xuserval(ix, str)
  2546. Xint ix;
  2547. XSTR *str;
  2548. X{
  2549. X    switch (ix) {
  2550. X
  2551. X    case UV_ora_cache:
  2552. X    str_numset(str, (double) ora_cache);
  2553. X    break;
  2554. X
  2555. X    case UV_ora_long:
  2556. X    str_numset(str, (double) ora_long);
  2557. X    break;
  2558. X
  2559. X    case UV_ora_trunc:
  2560. X    str_numset(str, (double) ora_trunc);
  2561. X    break;
  2562. X
  2563. X    case UV_ora_debug:
  2564. X#ifdef    DEBUGGING
  2565. X    str_set(str, (ora_debug == NULL) ? "" : ora_debug);
  2566. X#else
  2567. X    if (warn_on_debug)
  2568. X    {
  2569. X        warn("oraperl debugging not available");
  2570. X        warn_on_debug = 0;
  2571. X    }
  2572. X    str_set(str, "");    /* so the variable appears anyway */
  2573. X#endif
  2574. X    break;
  2575. X
  2576. X    case UV_ora_errno:
  2577. X    str_numset(str, (double) ora_errno);
  2578. X    break;
  2579. X
  2580. X    case UV_ora_verno:
  2581. X    str_numset(str, (double) (VERSION + (double) PATCHLEVEL / 1000));
  2582. X    break;
  2583. X
  2584. X    case UV_ora_errstr:
  2585. X    {
  2586. X        int len;
  2587. X        char ertxt[132];
  2588. X
  2589. X        if (ora_errno < ORAP_ERRMIN)
  2590. X        {
  2591. X            oermsg(ora_errno, ertxt);
  2592. X            if (ertxt[len = (strlen(ertxt) - 1)] == '\n')
  2593. X            {
  2594. X                ertxt[len] = '\0';
  2595. X            }
  2596. X            str_set(str, ertxt);
  2597. X        }
  2598. X        else if((ora_errno == ORAP_ERRMIN) || (ora_errno > ORAP_ERRMAX))
  2599. X        {
  2600. X            sprintf(ertxt, "unknown error %d", ora_errno);
  2601. X            str_set(str, ertxt);
  2602. X        }
  2603. X        else
  2604. X        {
  2605. X            str_set(str, ora_errlist[ora_errno - ORAP_ERRMIN]);
  2606. X        }
  2607. X    }
  2608. X    break;
  2609. X    }
  2610. X    return 0;
  2611. X}
  2612. END_OF_FILE
  2613.   if test 11035 -ne `wc -c <'oracle.mus'`; then
  2614.     echo shar: \"'oracle.mus'\" unpacked with wrong size!
  2615.   fi
  2616.   # end of 'oracle.mus'
  2617. fi
  2618. if test ! -d 'testdir' ; then
  2619.     echo shar: Creating directory \"'testdir'\"
  2620.     mkdir 'testdir'
  2621. fi
  2622. echo shar: End of archive 1 \(of 5\).
  2623. cp /dev/null ark1isdone
  2624. MISSING=""
  2625. for I in 1 2 3 4 5 ; do
  2626.     if test ! -f ark${I}isdone ; then
  2627.     MISSING="${MISSING} ${I}"
  2628.     fi
  2629. done
  2630. if test "${MISSING}" = "" ; then
  2631.     echo You have unpacked all 5 archives.
  2632.     rm -f ark[1-9]isdone
  2633. else
  2634.     echo You still must unpack the following archives:
  2635.     echo "        " ${MISSING}
  2636. fi
  2637. exit 0
  2638. exit 0 # Just in case...
  2639.