home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / tclx / part17 < prev    next >
Encoding:
Text File  |  1991-11-19  |  51.5 KB  |  1,777 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v26i017:  tclx - extensions and on-line help for tcl 6.1, Part17/23
  4. Message-ID: <1991Nov19.135603.1330@sparky.imd.sterling.com>
  5. X-Md4-Signature: 2d61823dde25fd3992cf7a7929335972
  6. Date: Tue, 19 Nov 1991 13:56:03 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 26, Issue 17
  11. Archive-name: tclx/part17
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 17 (of 23)."
  21. # Contents:  extended/src/fmath.c extended/src/regexputil.c
  22. #   extended/src/unixcmds.c
  23. # Wrapped by karl@one on Wed Nov 13 21:50:29 1991
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'extended/src/fmath.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'extended/src/fmath.c'\"
  27. else
  28. echo shar: Extracting \"'extended/src/fmath.c'\" \(16292 characters\)
  29. sed "s/^X//" >'extended/src/fmath.c' <<'END_OF_FILE'
  30. X/* 
  31. X * fmath.c --
  32. X *
  33. X *      Contains the TCL trig and floating point math functions.
  34. X *---------------------------------------------------------------------------
  35. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  36. X *
  37. X * Permission to use, copy, modify, and distribute this software and its
  38. X * documentation for any purpose and without fee is hereby granted, provided
  39. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  40. X * Mark Diekhans make no representations about the suitability of this
  41. X * software for any purpose.  It is provided "as is" without express or
  42. X * implied warranty.
  43. X */
  44. X
  45. X#include "tclExtdInt.h"
  46. X#include <math.h>
  47. X
  48. X/*
  49. X * Flag used to indicate if a floating point math routine is currently being
  50. X * executed.  Used to determine if a fmatherr belongs to Tcl.
  51. X */
  52. Xstatic int G_inTclFPMath = FALSE;
  53. X
  54. X/*
  55. X * Flag indicating if a floating point math error occured during the execution
  56. X * of a library routine called by a Tcl command.  Will not be set by the trap
  57. X * handler if the error did not occur while the `G_inTclFPMath' flag was
  58. X * set.  If the error did occur the error type and the name of the function
  59. X * that got the error are save here.
  60. X */
  61. Xstatic int   G_gotTclFPMathErr = FALSE;
  62. Xstatic char *G_functionName;
  63. Xstatic int   G_errorType;
  64. X
  65. X/*
  66. X * Prototypes of internal functions.
  67. X */
  68. Xint
  69. XTcl_UnaryFloatFunction _ANSI_ARGS_((Tcl_Interp *interp,
  70. X                                    int         argc,
  71. X                                    char      **argv,
  72. X                                    double (*function)()));
  73. X
  74. X
  75. X/*
  76. X *----------------------------------------------------------------------
  77. X *
  78. X * ReturnFPMathError --
  79. X *    Routine to set an interpreter result to contain a floating point
  80. X * math error message.  Will clear the `G_gotTclFPMathErr' flag.
  81. X * This routine always returns the value TCL_ERROR, so if can be called
  82. X * as the argument to `return'.
  83. X *
  84. X * Globals:
  85. X *   o G_gotTclFPMathErr (O) - Flag indicating an error occured, will be 
  86. X *     cleared.
  87. X *   o G_functionName (I) - Name of function that got the error.
  88. X *   o G_errorType (I) - Type of error that occured.
  89. X *----------------------------------------------------------------------
  90. X */
  91. Xstatic int
  92. XReturnFPMathError (interp)
  93. X    Tcl_Interp *interp;
  94. X{
  95. X    char *errorMsg;
  96. X
  97. X    switch (G_errorType) {
  98. X       case DOMAIN: 
  99. X           errorMsg = "domain";
  100. X           break;
  101. X       case SING:
  102. X           errorMsg = "singularity";
  103. X           break;
  104. X       case OVERFLOW:
  105. X           errorMsg = "overflow";
  106. X           break;
  107. X       case UNDERFLOW:
  108. X           errorMsg = "underflow";
  109. X           break;
  110. X       case TLOSS:
  111. X       case PLOSS:
  112. X           errorMsg = "loss of significance";
  113. X           break;
  114. X    }
  115. X    sprintf (interp->result, "%s: floating point %s error", G_functionName,
  116. X             errorMsg);
  117. X    G_gotTclFPMathErr = FALSE;  /* Clear the flag. */
  118. X    return TCL_ERROR;
  119. X}
  120. X
  121. X/*
  122. X *----------------------------------------------------------------------
  123. X *
  124. X * Tcl_MathError --
  125. X *    Tcl math error handler, should be called by an application `matherr'
  126. X *    routine to determine if an error was caused by Tcl code or by other
  127. X *    code in the application.  If the error occured in Tcl code, flags will
  128. X *    be set so that a standard Tcl interpreter error can be returned.
  129. X *
  130. X * Paramenter:
  131. X *   o functionName (I) - The name of the function that got the error.  From
  132. X *     the exception structure supplied to matherr.
  133. X *   o errorType (I) - The type of error that occured.  From the exception 
  134. X *     structure supplied to matherr.
  135. X * Results:
  136. X *      Returns TRUE if the error was in Tcl code, in which case the
  137. X *   matherr routine calling this function should return non-zero so no
  138. X *   error message will be generated.  FALSE if the error was not in Tcl
  139. X *   code, in which case the matherr routine can handle the error in any
  140. X *   manner it choses.
  141. X *
  142. X *----------------------------------------------------------------------
  143. X */
  144. Xint
  145. XTcl_MathError (functionName, errorType)
  146. X    char *functionName;
  147. X    int   errorType;
  148. X{
  149. X
  150. X  if (G_inTclFPMath) {
  151. X      G_gotTclFPMathErr = TRUE;
  152. X      G_functionName = functionName;
  153. X      G_errorType = errorType;
  154. X      return TRUE;
  155. X  } else
  156. X     return FALSE;
  157. X  
  158. X}
  159. X
  160. X/*
  161. X *----------------------------------------------------------------------
  162. X *
  163. X * Tcl_UnaryFloatFunction --
  164. X *    Helper routine that implements Tcl unary floating point
  165. X *     functions by validating parameters, converting the
  166. X *     argument, applying the function (the address of which
  167. X *     is passed as an argument), and converting the result to
  168. X *     a string and storing it in the result buffer
  169. X *
  170. X * Results:
  171. X *      Returns TCL_OK if number is present, conversion succeeded,
  172. X *        the function was performed, etc.
  173. X *      Return TCL_ERROR for any error; an appropriate error message
  174. X *        is placed in the result string in this case.
  175. X *
  176. X *----------------------------------------------------------------------
  177. X */
  178. Xstatic int
  179. XTcl_UnaryFloatFunction(interp, argc, argv, function)
  180. X    Tcl_Interp *interp;
  181. X    int         argc;
  182. X    char      **argv;
  183. X    double (*function)();
  184. X{
  185. X    double dbVal;
  186. X
  187. X    if (argc != 2) {
  188. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " val",
  189. X                          (char *) NULL);
  190. X        return TCL_ERROR;
  191. X    }
  192. X
  193. X    if (Tcl_GetDouble (interp, argv[1], &dbVal) != TCL_OK)
  194. X        return TCL_ERROR;
  195. X
  196. X    G_inTclFPMath = TRUE;
  197. X    sprintf(interp->result, "%g", (*function)(dbVal));
  198. X    G_inTclFPMath = FALSE;
  199. X
  200. X    if (G_gotTclFPMathErr)
  201. X        return ReturnFPMathError (interp);
  202. X
  203. X    return TCL_OK;
  204. X}
  205. X
  206. X/*
  207. X *----------------------------------------------------------------------
  208. X *
  209. X * Tcl_AcosCmd --
  210. X *    Implements the TCL arccosine command:
  211. X *        acos num
  212. X *
  213. X * Results:
  214. X *      Returns TCL_OK if number is present and conversion succeeds.
  215. X *
  216. X *----------------------------------------------------------------------
  217. X */
  218. Xint
  219. XTcl_AcosCmd(clientData, interp, argc, argv)
  220. X    ClientData  clientData;
  221. X    Tcl_Interp *interp;
  222. X    int         argc;
  223. X    char      **argv;
  224. X{
  225. X    return Tcl_UnaryFloatFunction(interp, argc, argv, acos);
  226. X}
  227. X
  228. X/*
  229. X *----------------------------------------------------------------------
  230. X *
  231. X * Tcl_AsinCmd --
  232. X *    Implements the TCL arcsin command:
  233. X *        asin num
  234. X *
  235. X * Results:
  236. X *      Returns TCL_OK if number is present and conversion succeeds.
  237. X *
  238. X *----------------------------------------------------------------------
  239. X */
  240. Xint
  241. XTcl_AsinCmd(clientData, interp, argc, argv)
  242. X    ClientData  clientData;
  243. X    Tcl_Interp *interp;
  244. X    int         argc;
  245. X    char      **argv;
  246. X{
  247. X    return Tcl_UnaryFloatFunction(interp, argc, argv, asin);
  248. X}
  249. X
  250. X/*
  251. X *----------------------------------------------------------------------
  252. X *
  253. X * Tcl_AtanCmd --
  254. X *    Implements the TCL arctangent command:
  255. X *        atan num
  256. X *
  257. X * Results:
  258. X *      Returns TCL_OK if number is present and conversion succeeds.
  259. X *
  260. X *----------------------------------------------------------------------
  261. X */
  262. Xint
  263. XTcl_AtanCmd(clientData, interp, argc, argv)
  264. X    ClientData  clientData;
  265. X    Tcl_Interp *interp;
  266. X    int         argc;
  267. X    char      **argv;
  268. X{
  269. X    return Tcl_UnaryFloatFunction(interp, argc, argv, atan);
  270. X}
  271. X
  272. X/*
  273. X *----------------------------------------------------------------------
  274. X *
  275. X * Tcl_CosCmd --
  276. X *    Implements the TCL cosine command:
  277. X *        cos num
  278. X *
  279. X * Results:
  280. X *      Returns TCL_OK if number is present and conversion succeeds.
  281. X *
  282. X *----------------------------------------------------------------------
  283. X */
  284. Xint
  285. XTcl_CosCmd(clientData, interp, argc, argv)
  286. X    ClientData  clientData;
  287. X    Tcl_Interp *interp;
  288. X    int         argc;
  289. X    char      **argv;
  290. X{
  291. X    return Tcl_UnaryFloatFunction(interp, argc, argv, cos);
  292. X}
  293. X
  294. X/*
  295. X *----------------------------------------------------------------------
  296. X *
  297. X * Tcl_SinCmd --
  298. X *    Implements the TCL sin command:
  299. X *        sin num
  300. X *
  301. X * Results:
  302. X *      Returns TCL_OK if number is present and conversion succeeds.
  303. X *
  304. X *----------------------------------------------------------------------
  305. X */
  306. Xint
  307. XTcl_SinCmd(clientData, interp, argc, argv)
  308. X    ClientData  clientData;
  309. X    Tcl_Interp *interp;
  310. X    int         argc;
  311. X    char      **argv;
  312. X{
  313. X    return Tcl_UnaryFloatFunction(interp, argc, argv, sin);
  314. X}
  315. X
  316. X/*
  317. X *----------------------------------------------------------------------
  318. X *
  319. X * Tcl_TanCmd --
  320. X *    Implements the TCL tangent command:
  321. X *        tan num
  322. X *
  323. X * Results:
  324. X *      Returns TCL_OK if number is present and conversion succeeds.
  325. X *
  326. X *----------------------------------------------------------------------
  327. X */
  328. Xint
  329. XTcl_TanCmd(clientData, interp, argc, argv)
  330. X    ClientData  clientData;
  331. X    Tcl_Interp *interp;
  332. X    int         argc;
  333. X    char      **argv;
  334. X{
  335. X    return Tcl_UnaryFloatFunction(interp, argc, argv, tan);
  336. X}
  337. X
  338. X/*
  339. X *----------------------------------------------------------------------
  340. X *
  341. X * Tcl_CoshCmd --
  342. X *    Implements the TCL hyperbolic cosine command:
  343. X *        cosh num
  344. X *
  345. X * Results:
  346. X *      Returns TCL_OK if number is present and conversion succeeds.
  347. X *
  348. X *----------------------------------------------------------------------
  349. X */
  350. Xint
  351. XTcl_CoshCmd(clientData, interp, argc, argv)
  352. X    ClientData  clientData;
  353. X    Tcl_Interp *interp;
  354. X    int         argc;
  355. X    char      **argv;
  356. X{
  357. X    return Tcl_UnaryFloatFunction(interp, argc, argv, cosh);
  358. X}
  359. X
  360. X/*
  361. X *----------------------------------------------------------------------
  362. X *
  363. X * Tcl_SinhCmd --
  364. X *    Implements the TCL hyperbolic sin command:
  365. X *        sinh num
  366. X *
  367. X * Results:
  368. X *      Returns TCL_OK if number is present and conversion succeeds.
  369. X *
  370. X *----------------------------------------------------------------------
  371. X */
  372. Xint
  373. XTcl_SinhCmd(clientData, interp, argc, argv)
  374. X    ClientData  clientData;
  375. X    Tcl_Interp *interp;
  376. X    int         argc;
  377. X    char      **argv;
  378. X{
  379. X    return Tcl_UnaryFloatFunction(interp, argc, argv, sinh);
  380. X}
  381. X
  382. X/*
  383. X *----------------------------------------------------------------------
  384. X *
  385. X * Tcl_TanhCmd --
  386. X *    Implements the TCL hyperbolic tangent command:
  387. X *        tanh num
  388. X *
  389. X * Results:
  390. X *      Returns TCL_OK if number is present and conversion succeeds.
  391. X *
  392. X *----------------------------------------------------------------------
  393. X */
  394. Xint
  395. XTcl_TanhCmd(clientData, interp, argc, argv)
  396. X    ClientData  clientData;
  397. X    Tcl_Interp *interp;
  398. X    int         argc;
  399. X    char      **argv;
  400. X{
  401. X    return Tcl_UnaryFloatFunction(interp, argc, argv, tanh);
  402. X}
  403. X
  404. X/*
  405. X *----------------------------------------------------------------------
  406. X *
  407. X * Tcl_ExpCmd --
  408. X *    Implements the TCL exponent command:
  409. X *        exp num
  410. X *
  411. X * Results:
  412. X *      Returns TCL_OK if number is present and conversion succeeds.
  413. X *
  414. X *----------------------------------------------------------------------
  415. X */
  416. Xint
  417. XTcl_ExpCmd(clientData, interp, argc, argv)
  418. X    ClientData  clientData;
  419. X    Tcl_Interp *interp;
  420. X    int         argc;
  421. X    char      **argv;
  422. X{
  423. X    return Tcl_UnaryFloatFunction(interp, argc, argv, exp);
  424. X}
  425. X
  426. X/*
  427. X *----------------------------------------------------------------------
  428. X *
  429. X * Tcl_LogCmd --
  430. X *    Implements the TCL logarithm command:
  431. X *        log num
  432. X *
  433. X * Results:
  434. X *      Returns TCL_OK if number is present and conversion succeeds.
  435. X *
  436. X *----------------------------------------------------------------------
  437. X */
  438. Xint
  439. XTcl_LogCmd(clientData, interp, argc, argv)
  440. X    ClientData  clientData;
  441. X    Tcl_Interp *interp;
  442. X    int         argc;
  443. X    char      **argv;
  444. X{
  445. X    return Tcl_UnaryFloatFunction(interp, argc, argv, log);
  446. X}
  447. X
  448. X/*
  449. X *----------------------------------------------------------------------
  450. X *
  451. X * Tcl_Log10Cmd --
  452. X *    Implements the TCL base-10 logarithm command:
  453. X *        log10 num
  454. X *
  455. X * Results:
  456. X *      Returns TCL_OK if number is present and conversion succeeds.
  457. X *
  458. X *----------------------------------------------------------------------
  459. X */
  460. Xint
  461. XTcl_Log10Cmd(clientData, interp, argc, argv)
  462. X    ClientData  clientData;
  463. X    Tcl_Interp *interp;
  464. X    int         argc;
  465. X    char      **argv;
  466. X{
  467. X    return Tcl_UnaryFloatFunction(interp, argc, argv, log10);
  468. X}
  469. X
  470. X/*
  471. X *----------------------------------------------------------------------
  472. X *
  473. X * Tcl_SqrtCmd --
  474. X *    Implements the TCL square root command:
  475. X *        sqrt num
  476. X *
  477. X * Results:
  478. X *      Returns TCL_OK if number is present and conversion succeeds.
  479. X *
  480. X *----------------------------------------------------------------------
  481. X */
  482. Xint
  483. XTcl_SqrtCmd(clientData, interp, argc, argv)
  484. X    ClientData  clientData;
  485. X    Tcl_Interp *interp;
  486. X    int         argc;
  487. X    char      **argv;
  488. X{
  489. X    return Tcl_UnaryFloatFunction(interp, argc, argv, sqrt);
  490. X}
  491. X
  492. X/*
  493. X *----------------------------------------------------------------------
  494. X *
  495. X * Tcl_FabsCmd --
  496. X *    Implements the TCL floating point absolute value command:
  497. X *        fabs num
  498. X *
  499. X * Results:
  500. X *      Returns TCL_OK if number is present and conversion succeeds.
  501. X *
  502. X *----------------------------------------------------------------------
  503. X */
  504. Xint
  505. XTcl_FabsCmd(clientData, interp, argc, argv)
  506. X    ClientData  clientData;
  507. X    Tcl_Interp *interp;
  508. X    int         argc;
  509. X    char      **argv;
  510. X{
  511. X    return Tcl_UnaryFloatFunction(interp, argc, argv, fabs);
  512. X}
  513. X
  514. X/*
  515. X *----------------------------------------------------------------------
  516. X *
  517. X * Tcl_FloorCmd --
  518. X *    Implements the TCL floor command:
  519. X *        floor num
  520. X *
  521. X * Results:
  522. X *      Returns TCL_OK if number is present and conversion succeeds.
  523. X *
  524. X *----------------------------------------------------------------------
  525. X */
  526. Xint
  527. XTcl_FloorCmd(clientData, interp, argc, argv)
  528. X    ClientData  clientData;
  529. X    Tcl_Interp *interp;
  530. X    int         argc;
  531. X    char      **argv;
  532. X{
  533. X    return Tcl_UnaryFloatFunction(interp, argc, argv, floor);
  534. X}
  535. X
  536. X/*
  537. X *----------------------------------------------------------------------
  538. X *
  539. X * Tcl_CeilCmd --
  540. X *    Implements the TCL ceil command:
  541. X *        ceil num
  542. X *
  543. X * Results:
  544. X *      Returns TCL_OK if number is present and conversion succeeds.
  545. X *
  546. X *----------------------------------------------------------------------
  547. X */
  548. Xint
  549. XTcl_CeilCmd(clientData, interp, argc, argv)
  550. X    ClientData  clientData;
  551. X    Tcl_Interp *interp;
  552. X    int         argc;
  553. X    char      **argv;
  554. X{
  555. X    return Tcl_UnaryFloatFunction(interp, argc, argv, ceil);
  556. X}
  557. X
  558. X/*
  559. X *----------------------------------------------------------------------
  560. X *
  561. X * Tcl_FmodCmd --
  562. X *    Implements the TCL floating modulo command:
  563. X *        fmod num1 num2
  564. X *
  565. X * Results:
  566. X *      Returns TCL_OK if number is present and conversion succeeds.
  567. X *
  568. X *----------------------------------------------------------------------
  569. X */
  570. Xint
  571. XTcl_FmodCmd(clientData, interp, argc, argv)
  572. X    ClientData  clientData;
  573. X    Tcl_Interp *interp;
  574. X    int         argc;
  575. X    char      **argv;
  576. X{
  577. X    double dbVal, dbDivisor;
  578. X
  579. X    if (argc != 3) {
  580. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " val divisor",
  581. X                          (char *) NULL);
  582. X        return TCL_ERROR;
  583. X    }
  584. X
  585. X    if (Tcl_GetDouble (interp, argv[1], &dbVal) != TCL_OK)
  586. X        return TCL_ERROR;
  587. X
  588. X    if (Tcl_GetDouble (interp, argv[2], &dbDivisor) != TCL_OK)
  589. X        return TCL_ERROR;
  590. X
  591. X    G_inTclFPMath = TRUE;
  592. X    sprintf(interp->result, "%g", fmod(dbVal,dbDivisor));
  593. X    G_inTclFPMath = FALSE;
  594. X
  595. X    if (G_gotTclFPMathErr)
  596. X        return ReturnFPMathError (interp);
  597. X
  598. X    return TCL_OK;
  599. X}
  600. X
  601. X/*
  602. X *----------------------------------------------------------------------
  603. X *
  604. X * Tcl_PowCmd --
  605. X *    Implements the TCL power (exponentiation) command:
  606. X *        pow num1 num2
  607. X *
  608. X * Results:
  609. X *      Returns TCL_OK if number is present and conversion succeeds.
  610. X *
  611. X *----------------------------------------------------------------------
  612. X */
  613. Xint
  614. XTcl_PowCmd(clientData, interp, argc, argv)
  615. X    ClientData  clientData;
  616. X    Tcl_Interp *interp;
  617. X    int         argc;
  618. X    char      **argv;
  619. X{
  620. X    double dbVal, dbExp;
  621. X
  622. X    if (argc != 3) {
  623. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " val exp",
  624. X                          (char *) NULL);
  625. X        return TCL_ERROR;
  626. X    }
  627. X
  628. X    if (Tcl_GetDouble (interp, argv[1], &dbVal) != TCL_OK)
  629. X        return TCL_ERROR;
  630. X
  631. X    if (Tcl_GetDouble (interp, argv[2], &dbExp) != TCL_OK)
  632. X        return TCL_ERROR;
  633. X
  634. X    G_inTclFPMath = TRUE;
  635. X    sprintf(interp->result, "%g", pow(dbVal,dbExp));
  636. X    G_inTclFPMath = FALSE;
  637. X
  638. X    if (G_gotTclFPMathErr)
  639. X        return ReturnFPMathError (interp);
  640. X
  641. X    return TCL_OK;
  642. X}
  643. END_OF_FILE
  644. if test 16292 -ne `wc -c <'extended/src/fmath.c'`; then
  645.     echo shar: \"'extended/src/fmath.c'\" unpacked with wrong size!
  646. fi
  647. # end of 'extended/src/fmath.c'
  648. fi
  649. if test -f 'extended/src/regexputil.c' -a "${1}" != "-c" ; then 
  650.   echo shar: Will not clobber existing file \"'extended/src/regexputil.c'\"
  651. else
  652. echo shar: Extracting \"'extended/src/regexputil.c'\" \(15466 characters\)
  653. sed "s/^X//" >'extended/src/regexputil.c' <<'END_OF_FILE'
  654. X/*
  655. X * regexputil.c --
  656. X *
  657. X * Tcl regular expression pattern matching utilities.
  658. X *---------------------------------------------------------------------------
  659. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  660. X *
  661. X * Permission to use, copy, modify, and distribute this software and its
  662. X * documentation for any purpose and without fee is hereby granted, provided
  663. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  664. X * Mark Diekhans make no representations about the suitability of this
  665. X * software for any purpose.  It is provided "as is" without express or
  666. X * implied warranty.
  667. X *---------------------------------------------------------------------------
  668. X * Boyer-Moore code from: 
  669. X *     torek-boyer-moore/27-Aug-90 by
  670. X *     chris@mimsy.umd.edu (Chris Torek)
  671. X */
  672. X
  673. X#include "tclExtdInt.h"
  674. X#include "regexp.h"
  675. X
  676. X/*
  677. X * This is declared in tclUtil.c.  Must be set to NULL before compiling
  678. X * a regular expressions.
  679. X */
  680. Xextern char *tclRegexpError;
  681. X
  682. X/*
  683. X * Meta-characters for regular expression
  684. X */
  685. X#define REXP_META               "^$.[()|?+*\\"
  686. X#define REXP_META_NO_BRACKET    "^$.()|?+*\\"
  687. X
  688. X#ifndef CHAR_MAX
  689. X#    define CHAR_MAX 255
  690. X#endif
  691. X
  692. X/*
  693. X * Prototypes of internal functions.
  694. X */
  695. X
  696. Xchar *
  697. XBoyerMooreCompile _ANSI_ARGS_((char *pat,
  698. X                                  int patlen));
  699. X
  700. Xchar *
  701. XBoyerMooreExecute _ANSI_ARGS_((char     *text,
  702. X                               unsigned  textlen,
  703. X                               char     *compPtr,
  704. X                               unsigned *patLenP));
  705. X
  706. X
  707. X/*
  708. X * Boyer-Moore search: input is `text' (a string) and its length,
  709. X * and a `pattern' (another string) and its length.
  710. X *
  711. X * The linear setup cost of this function is approximately 256 + patlen.
  712. X * Afterwards, however, the average cost is O(textlen/patlen), and the
  713. X * worst case is O(textlen+patlen).
  714. X *
  715. X * The Boyer-Moore algorithm works by observing that, for each position
  716. X * in the text, if the character there does *not* occur somewhere in the
  717. X * search pattern, no comparisons including that character will match.
  718. X * That is, given the text "hello world..." and the pattern "goodbye", the
  719. X * `w' in `world' means that none of `hello w', `ello wo', `llo wor',
  720. X * `lo worl', `o world', ` world.', and `world..' can match.  In fact,
  721. X * exactly patlen strings are certain not to match.  We can discover this
  722. X * simply by looking at the patlen'th character.  Furthermore, even if
  723. X * the text character does occur, it may be that it rules out some number
  724. X * of other matches.  Again, we can discover this by doing the match
  725. X * `backwards'.
  726. X *
  727. X * We set up a table of deltas for each possible character, with
  728. X * delta[character] being patlen for characters not in the pattern,
  729. X * less for characters in the pattern, growing progressively smaller
  730. X * as we near the end of the pattern.  Matching then works as follows:
  731. X *
  732. X *       0         1         2         3
  733. X *       01234567890123456789012345678901234567
  734. X *      "Here is the string being searched into"        (text)
  735. X *       ------                                         (pos = [0..5])
  736. X *      "string"                                        (pat)
  737. X *      654321-                                         (deltas)
  738. X *
  739. X * (the delta for `-' will be derived below).
  740. X *
  741. X * Positions 0..5 end with `i', which is not the `g' we want.  `i' does
  742. X * appear in `string', but two characters before the end.  We skip
  743. X * forward so as to make the `i's match up:
  744. X *
  745. X *      "Here is the string being searched into"        (text)
  746. X *        "string"                                      (pos = [2..7])
  747. X *
  748. X * Next we find that ` ' and `g' do not match.  Since ` ' does not appear
  749. X * in the pattern at all, we can skip forward 6:
  750. X *
  751. X *      "Here is the string being searched into"        (text)
  752. X *              "string"                                (pos = [8..13])
  753. X *
  754. X * Comparing `t' vs `g', we again find no match, and so we obtain the
  755. X * delta for `t', which is 4.  We skip to position 17:
  756. X *
  757. X *      "Here is the string being searched into"        (text)
  758. X *                  "string"                            (pos = [12..17])
  759. X *
  760. X * It thus takes only four steps to move the search point forward to the
  761. X * match, in this case.
  762. X *
  763. X * If the pattern has a recurring character, we must set the delta for
  764. X * that character to the distance of the one closest to the end:
  765. X *
  766. X *      "befuddle the cat"      (text)
  767. X *      "fuddle"                (pos = [0..5])
  768. X *      654321-                 (delta)
  769. X *
  770. X * We want the next search to line the `d's up like this:
  771. X *
  772. X *      "befuddle the cat"      (text)
  773. X *        "fuddle"              (pos = [2..7])
  774. X *
  775. X * and not like this:
  776. X *
  777. X *      "befuddle the cat"      (text)
  778. X *         "fuddle"             (pos = [3..8])
  779. X *
  780. X * so we take the smaller delta for d, i.e., 2.
  781. X *
  782. X * The last task is computing the delta we have noted above as `-':
  783. X *
  784. X *      "candlesticks"          (text)
  785. X *      "hand"                  (pos = [0..3])
  786. X *      4321-                   (delta)
  787. X *
  788. X * Here the `d' in `hand' matches the `d' in `candlesticks', but the
  789. X * strings differ.  Since there are no other `d's in `hand', we know
  790. X * that none of (cand,andl,ndle,dles) can match, and thus we want this
  791. X * delta to be 4 (the length of the pattern).  But if we had, e.g.:
  792. X *
  793. X *      "candlesticks"          (text)
  794. X *      "deed"                  (pos = [0..3])
  795. X *      4321-                   (delta)
  796. X *
  797. X * then we should advance to line up the other `d':
  798. X *
  799. X *      "candlesticks"          (text)
  800. X *         "deed"               (pos = [3..6])
  801. X *
  802. X * As this suggests, the delta should be that for the `d' nearest the
  803. X * end, but not including the end.  This is easily managed by setting up
  804. X * a delta table as follows:
  805. X *
  806. X *      for int:c in [0..255] { delta[c] = patlen; };
  807. X *      for int:x in [0..patlen-1) { delta[pat[x]] = patlen - (x + 1); };
  808. X *
  809. X * delta[pat[patlen-1]] is never written, so the last letter inherits the
  810. X * delta from an earlier iteration or from the previous loop.
  811. X *
  812. X * NB: the nonsense with `deltaspace' below exists merely because gcc
  813. X * does a horrible job of common subexpression elimination (it does not
  814. X * notice that the array is at a constant stack address).
  815. X */
  816. X
  817. Xstruct compiled_search_struct {
  818. X        unsigned patlen;
  819. X        unsigned deltaspace[CHAR_MAX + 1];
  820. X};
  821. X
  822. X
  823. Xstatic char *
  824. XBoyerMooreCompile (pat, patlen)
  825. X    char *pat;
  826. X    int   patlen;
  827. X{
  828. X        register unsigned char *p, *t;
  829. X        register unsigned i, p1, j, *delta;
  830. X        struct compiled_search_struct *cp;
  831. X        int alloc_len;
  832. X
  833. X        /* algorithm fails if pattern is empty */
  834. X        if ((p1 = patlen) == 0)
  835. X                return (NULL);
  836. X
  837. X        alloc_len = sizeof(struct compiled_search_struct) + patlen + 1;
  838. X        cp = (struct compiled_search_struct *)ckalloc(alloc_len);
  839. X
  840. X        strncpy((char *)cp+sizeof(struct compiled_search_struct), pat, patlen);
  841. X        *((char *)cp+alloc_len-1) = '\0';
  842. X
  843. X        /* set up deltas */
  844. X        delta = cp->deltaspace;
  845. X
  846. X        for (i = 0; i <= CHAR_MAX; i++)
  847. X                delta[i] = p1;
  848. X
  849. X        for (p = (unsigned char *)pat, i = p1; --i > 0;)
  850. X                delta[*p++] = i;
  851. X
  852. X        cp->patlen = patlen;
  853. X        return((char*) cp);
  854. X}
  855. X
  856. Xstatic char *
  857. XBoyerMooreExecute (text, textlen, compPtr, patLenP)
  858. X        char     *text;
  859. X        unsigned  textlen;
  860. X        char     *compPtr;
  861. X        unsigned *patLenP;
  862. X{
  863. X        register unsigned char *p, *t;
  864. X        struct compiled_search_struct *csp = 
  865. X            (struct compiled_search_struct*) compPtr;
  866. X        register unsigned i, p1, j, *delta = csp->deltaspace;
  867. X        char *pat;
  868. X        unsigned patlen;
  869. X
  870. X        *patLenP = p1 = patlen = csp->patlen;
  871. X        /* code below fails (whenever i is unsigned) if pattern too long */
  872. X        if (p1 > textlen)
  873. X                return (NULL);
  874. X
  875. X        pat = (char *)csp + sizeof(struct compiled_search_struct);
  876. X        /*
  877. X         * From now on, we want patlen - 1.
  878. X         * In the loop below, p points to the end of the pattern,
  879. X         * t points to the end of the text to be tested against the
  880. X         * pattern, and i counts the amount of text remaining, not
  881. X         * including the part to be tested.
  882. X         */
  883. X        p1--;
  884. X        p = (unsigned char *)pat + p1;
  885. X        t = (unsigned char *)text + p1;
  886. X        i = textlen - patlen;
  887. X        for (;;) {
  888. X                if (*p == *t && 
  889. X                    memcmp((p - p1), (t - p1), p1) == 0)
  890. X                        return ((char *)t - p1);
  891. X                j = delta[*t];
  892. X                if (i < j)
  893. X                        break;
  894. X                i -= j;
  895. X                t += j;
  896. X        }
  897. X        return (NULL);
  898. X}
  899. X
  900. X
  901. X/*
  902. X *----------------------------------------------------------------------
  903. X *
  904. X * Tcl_RegExpClean --
  905. X *     Free all resources associated with a regular expression info 
  906. X *     structure..
  907. X *
  908. X *----------------------------------------------------------------------
  909. X */
  910. Xvoid
  911. XTcl_RegExpClean (regExpPtr)
  912. X    regexp_pt regExpPtr;
  913. X{
  914. X    if (regExpPtr->progPtr != NULL)
  915. X        ckfree ((char *) regExpPtr->progPtr);
  916. X    if (regExpPtr->boyerMoorePtr != NULL)
  917. X        ckfree ((char *) regExpPtr->boyerMoorePtr);
  918. X}
  919. X
  920. X/*
  921. X *----------------------------------------------------------------------
  922. X *
  923. X * FindNonRegExpSubStr
  924. X *     Find the largest substring that does not have any regular 
  925. X *     expression meta-characters and is not located within `[...]'.
  926. X *
  927. X *----------------------------------------------------------------------
  928. X */
  929. Xstatic void
  930. XFindNonRegExpSubStr (expression, subStrPtrPtr, subStrLenPtr)
  931. X    char  *expression;
  932. X    char **subStrPtrPtr;
  933. X    int   *subStrLenPtr;
  934. X{
  935. X    register char *subStrPtr = NULL;
  936. X    register char  subStrLen = 0;
  937. X    register char *scanPtr   = expression;
  938. X    register int   len;
  939. X
  940. X    while (*scanPtr != '\0') {
  941. X        len = strcspn (scanPtr, REXP_META);
  942. X        /*
  943. X         * If we are at a meta-character, by-pass till non-meta.  If we hit
  944. X         * a `[' then by-pass the entire `[...]' range, but be careful, could
  945. X         * have omitted `]'.
  946. X         */
  947. X        if (len == 0) {
  948. X            scanPtr += strspn (scanPtr, REXP_META_NO_BRACKET);
  949. X            if (*scanPtr == '[') {
  950. X                scanPtr += strcspn (scanPtr, "]");
  951. X                if (*scanPtr == ']')
  952. X                    scanPtr++;
  953. X            }          
  954. X        } else {
  955. X            if (len > subStrLen) {
  956. X                subStrPtr = scanPtr;
  957. X                subStrLen = len;
  958. X            }
  959. X            scanPtr += len;
  960. X        }
  961. X    }
  962. X    *subStrPtrPtr = subStrPtr;
  963. X    *subStrLenPtr = subStrLen;
  964. X}
  965. X
  966. X/*
  967. X *----------------------------------------------------------------------
  968. X *
  969. X * Tcl_RegExpCompile --
  970. X *     Compile a regular expression.
  971. X *
  972. X * Parameters:
  973. X *     o regExpPtr - Used to hold info on this regular expression.  If the
  974. X *       structure is being reused, it Tcl_RegExpClean should be called first.
  975. X *     o expression - Regular expression to compile.
  976. X *     o flags - The following flags are recognized:
  977. X *         o REXP_NO_CASE - Comparison will be regardless of case.
  978. X *         o REXP_BOTH_ALGORITHMS - If specified, a Boyer-Moore expression is 
  979. X *           compiled for the largest substring of the expression that does
  980. X *           not contain any meta-characters.  This is slows compiling, but
  981. X *           speeds up large searches.
  982. X *
  983. X * Results:
  984. X *     Standard TCL results.
  985. X *----------------------------------------------------------------------
  986. X */
  987. Xint
  988. XTcl_RegExpCompile (interp, regExpPtr, expression, flags)
  989. X    Tcl_Interp  *interp;
  990. X    regexp_pt    regExpPtr;
  991. X    char        *expression;
  992. X    int          flags;
  993. X{
  994. X    char *expBuf;
  995. X    int   anyMeta;
  996. X
  997. X    if (*expression == '\0') {
  998. X        Tcl_AppendResult (interp, "Null regular expression", (char *) NULL);
  999. X        return TCL_ERROR;
  1000. X    }
  1001. X
  1002. X    regExpPtr->progPtr = NULL;
  1003. X    regExpPtr->boyerMoorePtr = NULL;
  1004. X    regExpPtr->noCase = flags & REXP_NO_CASE;
  1005. X
  1006. X    if (flags & REXP_NO_CASE) {
  1007. X        expBuf = ckalloc (strlen (expression) + 1);
  1008. X        Tcl_DownShift (expBuf, expression);
  1009. X    } else
  1010. X        expBuf = expression;
  1011. X
  1012. X    anyMeta = strpbrk (expBuf, REXP_META) != NULL;
  1013. X
  1014. X    /*
  1015. X     * If no meta-characters, use Boyer-Moore string matching only.
  1016. X     */
  1017. X    if (!anyMeta) {
  1018. X        regExpPtr->boyerMoorePtr = BoyerMooreCompile (expBuf, strlen (expBuf));
  1019. X        goto okExitPoint;
  1020. X    }
  1021. X    /*
  1022. X     * Build a Boyer-Moore on the largest non-meta substring, if requested.
  1023. X     */
  1024. X    if (flags & REXP_BOTH_ALGORITHMS) {
  1025. X        char *subStrPtr;
  1026. X        int   subStrLen;
  1027. X        
  1028. X        FindNonRegExpSubStr (expBuf, &subStrPtr, &subStrLen);
  1029. X        if (subStrLen > 0)
  1030. X            regExpPtr->boyerMoorePtr = 
  1031. X                BoyerMooreCompile (subStrPtr, subStrLen);
  1032. X    }
  1033. X    
  1034. X    /*
  1035. X     * Compile meta-character containing regular expression.
  1036. X     */
  1037. X    tclRegexpError = NULL;
  1038. X    regExpPtr->progPtr = regcomp (expBuf);
  1039. X    if (tclRegexpError != NULL) {
  1040. X        if (flags & REXP_NO_CASE)
  1041. X            ckfree (expBuf);
  1042. X        Tcl_AppendResult (interp, "error in regular expression: ", 
  1043. X                          tclRegexpError, (char *) NULL);
  1044. X        if (flags & REXP_NO_CASE)
  1045. X            ckfree (expBuf);
  1046. X        Tcl_RegExpClean (regExpPtr);
  1047. X    }
  1048. X  
  1049. XokExitPoint: 
  1050. X    if (flags & REXP_NO_CASE)
  1051. X        ckfree (expBuf);
  1052. X    return TCL_OK;
  1053. X
  1054. X}
  1055. X
  1056. X/*
  1057. X *----------------------------------------------------------------------
  1058. X *
  1059. X * Tcl_RegExpExecute --
  1060. X *     Execute a regular expression compiled with Boyer-Moore and/or 
  1061. X *     regexp.
  1062. X *
  1063. X * Parameters:
  1064. X *     o regExpPtr - Used to hold info on this regular expression.
  1065. X *     o matchStrIn - String to match against the regular expression.
  1066. X *     o matchStrLower - Optional lower case version of the string.  If
  1067. X *       multiple no case matches are being done, time can be saved by
  1068. X *       down shifting the string in advance.  NULL if not a no-case 
  1069. X *       match or this procedure is to do the down shifting.
  1070. X *
  1071. X * Results:
  1072. X *     TRUE if a match, FALSE if it does not match.
  1073. X *
  1074. X *----------------------------------------------------------------------
  1075. X */
  1076. Xint
  1077. XTcl_RegExpExecute (interp, regExpPtr, matchStrIn, matchStrLower)
  1078. X    Tcl_Interp  *interp;
  1079. X    regexp_pt    regExpPtr;
  1080. X    char        *matchStrIn;
  1081. X    char        *matchStrLower;
  1082. X{
  1083. X    char *matchStr;
  1084. X    int   result;
  1085. X
  1086. X    if (regExpPtr->noCase) {
  1087. X        if (matchStrLower == NULL) {
  1088. X            matchStr = ckalloc (strlen (matchStrIn) + 1);
  1089. X            Tcl_DownShift (matchStr, matchStrIn);
  1090. X        } else
  1091. X            matchStr = matchStrLower;
  1092. X    } else
  1093. X        matchStr = matchStrIn;
  1094. X    /*
  1095. X     * If a Boyer-Moore pattern has been compiled, use that algorithm to test
  1096. X     * against the text.  If that passes, then test with the regexp if we have
  1097. X     * it.
  1098. X     */
  1099. X    if (regExpPtr->boyerMoorePtr != NULL) {
  1100. X        char     *startPtr;
  1101. X        unsigned  matchLen;
  1102. X
  1103. X        startPtr = BoyerMooreExecute (matchStr, strlen (matchStr), 
  1104. X                                      regExpPtr->boyerMoorePtr, &matchLen);
  1105. X        if (startPtr == NULL) {
  1106. X            result = FALSE;
  1107. X            goto exitPoint;
  1108. X        }
  1109. X        if (regExpPtr->progPtr == NULL) {
  1110. X            result = TRUE;  /* No regexp, its a match! */
  1111. X            goto exitPoint;
  1112. X        }
  1113. X    }
  1114. X    
  1115. X    /*
  1116. X     * Give it a go with full regular expressions
  1117. X     */
  1118. X    result = regexec (regExpPtr->progPtr, matchStr);
  1119. X
  1120. X    /*
  1121. X     * Clean up and return status here.
  1122. X     */
  1123. XexitPoint:
  1124. X    if ((regExpPtr->noCase) && (matchStrLower == NULL))
  1125. X        ckfree (matchStr);
  1126. X    return result;
  1127. X}
  1128. END_OF_FILE
  1129. if test 15466 -ne `wc -c <'extended/src/regexputil.c'`; then
  1130.     echo shar: \"'extended/src/regexputil.c'\" unpacked with wrong size!
  1131. fi
  1132. # end of 'extended/src/regexputil.c'
  1133. fi
  1134. if test -f 'extended/src/unixcmds.c' -a "${1}" != "-c" ; then 
  1135.   echo shar: Will not clobber existing file \"'extended/src/unixcmds.c'\"
  1136. else
  1137. echo shar: Extracting \"'extended/src/unixcmds.c'\" \(16058 characters\)
  1138. sed "s/^X//" >'extended/src/unixcmds.c' <<'END_OF_FILE'
  1139. X/*
  1140. X * unixcmds.c --
  1141. X *
  1142. X * Tcl commands to access unix library calls.
  1143. X *---------------------------------------------------------------------------
  1144. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  1145. X *
  1146. X * Permission to use, copy, modify, and distribute this software and its
  1147. X * documentation for any purpose and without fee is hereby granted, provided
  1148. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  1149. X * Mark Diekhans make no representations about the suitability of this
  1150. X * software for any purpose.  It is provided "as is" without express or
  1151. X * implied warranty.
  1152. X */
  1153. X
  1154. X#include "tclExtdInt.h"
  1155. X
  1156. X
  1157. X/*
  1158. X *----------------------------------------------------------------------
  1159. X *
  1160. X * Tcl_ExecvpCmd --
  1161. X *     Implements the TCL execvp command:
  1162. X *     execvp prog ["arg1...argN"]
  1163. X *
  1164. X * Results:
  1165. X *  Standard TCL results, may return the UNIX system error message.
  1166. X *
  1167. X *----------------------------------------------------------------------
  1168. X */
  1169. Xint
  1170. XTcl_ExecvpCmd (clientData, interp, argc, argv)
  1171. X    ClientData  clientData;
  1172. X    Tcl_Interp *interp;
  1173. X    int         argc;
  1174. X    char      **argv;
  1175. X{
  1176. X    if (argc < 2) {
  1177. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " prog [arg..]",
  1178. X                          (char *) NULL);
  1179. X        return TCL_ERROR;
  1180. X    }
  1181. X
  1182. X    /*
  1183. X     * Argv always ends in a null.
  1184. X     */
  1185. X    if (execvp (argv[1], &argv[1]) < 0) {
  1186. X        Tcl_AppendResult (interp, argv [0], ": ", argv [1], ": ",
  1187. X                          Tcl_UnixError (interp), (char *) NULL);
  1188. X        return TCL_ERROR;
  1189. X    }
  1190. X
  1191. X    panic ("no execvp");
  1192. X}
  1193. X
  1194. X/*
  1195. X *----------------------------------------------------------------------
  1196. X *
  1197. X * Tcl_ForkCmd --
  1198. X *     Implements the TCL fork command:
  1199. X *     fork
  1200. X *
  1201. X * Results:
  1202. X *  Standard TCL results, may return the UNIX system error message.
  1203. X *
  1204. X *----------------------------------------------------------------------
  1205. X */
  1206. Xint
  1207. XTcl_ForkCmd (clientData, interp, argc, argv)
  1208. X    ClientData  clientData;
  1209. X    Tcl_Interp *interp;
  1210. X    int         argc;
  1211. X    char      **argv;
  1212. X{
  1213. X    int pid;
  1214. X
  1215. X    if (argc != 1) {
  1216. X        Tcl_AppendResult (interp, "wrong # args: ", argv[0], (char *) NULL);
  1217. X        return TCL_ERROR;
  1218. X    }
  1219. X
  1220. X    pid = Tcl_Fork ();
  1221. X    if (pid < 0) {
  1222. X        Tcl_AppendResult (interp, argv [0], ": ", Tcl_UnixError (interp),
  1223. X                          (char *) NULL);
  1224. X        return TCL_ERROR;
  1225. X    }
  1226. X
  1227. X    sprintf(interp->result, "%d", pid);
  1228. X    return TCL_OK;
  1229. X}
  1230. X
  1231. X/*
  1232. X *----------------------------------------------------------------------
  1233. X *
  1234. X * Tcl_KillCmd --
  1235. X *     Implements the TCL kill command:
  1236. X *        kill [signal] proclist
  1237. X *
  1238. X * Results:
  1239. X *  Standard TCL results, may return the UNIX system error message.
  1240. X *
  1241. X *----------------------------------------------------------------------
  1242. X */
  1243. Xint
  1244. XTcl_KillCmd (clientData, interp, argc, argv)
  1245. X    ClientData  clientData;
  1246. X    Tcl_Interp *interp;
  1247. X    int     argc;
  1248. X    char      **argv;
  1249. X{
  1250. X    int    signalNum, idx, procId, procArgc, result = TCL_ERROR;
  1251. X    char **procArgv;
  1252. X
  1253. X    if ((argc < 2) || (argc > 3)) {
  1254. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1255. X                          " [signal] processlist", (char *) NULL);
  1256. X        return TCL_ERROR;
  1257. X    }
  1258. X
  1259. X    if (argc == 2)
  1260. X        signalNum = SIGTERM;
  1261. X    else {
  1262. X        if (!Tcl_StrToInt (argv[1], 0, &signalNum)) {
  1263. X            signalNum = Tcl_SigNameToNum (argv[1]);
  1264. X        }
  1265. X        if ((signalNum < 0) || (signalNum > NSIG)) {
  1266. X            Tcl_AppendResult (interp, argv [0], ": invalid signal",
  1267. X                              (char *) NULL);
  1268. X            return TCL_ERROR;
  1269. X        }
  1270. X    }
  1271. X
  1272. X    if (Tcl_SplitList (interp, argv [argc - 1], &procArgc, 
  1273. X                       &procArgv) != TCL_OK)
  1274. X        return TCL_ERROR;
  1275. X
  1276. X    for (idx = 0; idx < procArgc; idx++) {
  1277. X
  1278. X        if (Tcl_GetInt (interp, procArgv [idx], &procId) != TCL_OK)
  1279. X            goto exitPoint;
  1280. X
  1281. X        if (kill (procId, signalNum) < 0) {
  1282. X            Tcl_AppendResult (interp, argv [0], ": pid ", procArgv [idx],
  1283. X                              ": ", Tcl_UnixError (interp), (char *) NULL);
  1284. X            goto exitPoint;
  1285. X        }
  1286. X     }
  1287. X
  1288. X    result = TCL_OK;
  1289. XexitPoint:
  1290. X    ckfree ((char *) procArgv);
  1291. X    return result;
  1292. X}
  1293. X
  1294. X/*
  1295. X *----------------------------------------------------------------------
  1296. X *
  1297. X * Tcl_AlarmCmd --
  1298. X *     Implements the TCL Alarm command:
  1299. X *         Alarm seconds
  1300. X *
  1301. X * Results:
  1302. X *      Standard TCL results, may return the UNIX system error message.
  1303. X *
  1304. X *----------------------------------------------------------------------
  1305. X */
  1306. Xint
  1307. XTcl_AlarmCmd (clientData, interp, argc, argv)
  1308. X    ClientData  clientData;
  1309. X    Tcl_Interp *interp;
  1310. X    int         argc;
  1311. X    char      **argv;
  1312. X{
  1313. X    unsigned time;
  1314. X
  1315. X    if (argc != 2) {
  1316. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " seconds", 
  1317. X                          (char *) NULL);
  1318. X        return TCL_ERROR;
  1319. X    }
  1320. X
  1321. X    if (Tcl_GetInt (interp, argv[1], &time) != TCL_OK)
  1322. X        return TCL_ERROR;
  1323. X
  1324. X    sprintf (interp->result, "%d", alarm (time));
  1325. X    return TCL_OK;
  1326. X
  1327. X}
  1328. X
  1329. X/*
  1330. X *----------------------------------------------------------------------
  1331. X *
  1332. X * Tcl_SleepCmd --
  1333. X *     Implements the TCL sleep command:
  1334. X *         sleep seconds
  1335. X *
  1336. X * Results:
  1337. X *      Standard TCL results, may return the UNIX system error message.
  1338. X *
  1339. X *----------------------------------------------------------------------
  1340. X */
  1341. Xint
  1342. XTcl_SleepCmd (clientData, interp, argc, argv)
  1343. X    ClientData  clientData;
  1344. X    Tcl_Interp *interp;
  1345. X    int         argc;
  1346. X    char      **argv;
  1347. X{
  1348. X    unsigned time;
  1349. X
  1350. X    if (argc != 2) {
  1351. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " seconds", 
  1352. X                          (char *) NULL);
  1353. X        return TCL_ERROR;
  1354. X    }
  1355. X
  1356. X    if (Tcl_GetUnsigned (interp, argv[1], &time) != TCL_OK)
  1357. X        return TCL_ERROR;
  1358. X
  1359. X    sleep (time);
  1360. X    return TCL_OK;
  1361. X
  1362. X}
  1363. X
  1364. X/*
  1365. X *----------------------------------------------------------------------
  1366. X *
  1367. X * Tcl_SystemCmd --
  1368. X *     Implements the TCL system command:
  1369. X *     system command
  1370. X *
  1371. X * Results:
  1372. X *  Standard TCL results, may return the UNIX system error message.
  1373. X *
  1374. X *----------------------------------------------------------------------
  1375. X */
  1376. Xint
  1377. XTcl_SystemCmd (clientData, interp, argc, argv)
  1378. X    ClientData  clientData;
  1379. X    Tcl_Interp *interp;
  1380. X    int         argc;
  1381. X    char      **argv;
  1382. X{
  1383. X    int exitCode;
  1384. X
  1385. X    if (argc != 2) {
  1386. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " command",
  1387. X                          (char *) NULL);
  1388. X        return TCL_ERROR;
  1389. X    }
  1390. X
  1391. X    exitCode = Tcl_System (interp, argv[1]);
  1392. X    if (exitCode == -1)
  1393. X        return TCL_ERROR;
  1394. X    sprintf (interp->result, "%d", exitCode);
  1395. X    return TCL_OK;
  1396. X}
  1397. X
  1398. X/*
  1399. X *----------------------------------------------------------------------
  1400. X *
  1401. X * Tcl_TimesCmd --
  1402. X *     Implements the TCL times command:
  1403. X *     times
  1404. X *
  1405. X * Results:
  1406. X *  Standard TCL results.
  1407. X *
  1408. X *----------------------------------------------------------------------
  1409. X */
  1410. Xint
  1411. XTcl_TimesCmd (clientData, interp, argc, argv)
  1412. X    ClientData  clientData;
  1413. X    Tcl_Interp *interp;
  1414. X    int         argc;
  1415. X    char      **argv;
  1416. X{
  1417. X    struct tms tm;
  1418. X
  1419. X    /*
  1420. X     * Precompute milliseconds-per-tick, the " + CLK_TCK / 2" bit gets it to
  1421. X     * round off instead of truncate.
  1422. X     */
  1423. X#define MS_PER_TICK ((1000 + CLK_TCK/2) / CLK_TCK)
  1424. X
  1425. X    if (argc != 1) {
  1426. X        Tcl_AppendResult (interp, "wrong # args: ", argv[0], (char *) NULL);
  1427. X        return TCL_ERROR;
  1428. X    }
  1429. X
  1430. X    times(&tm);
  1431. X
  1432. X    sprintf(interp->result, "%ld %ld %ld %ld", 
  1433. X            tm.tms_utime  * MS_PER_TICK, 
  1434. X            tm.tms_stime  * MS_PER_TICK, 
  1435. X            tm.tms_cutime * MS_PER_TICK, 
  1436. X            tm.tms_cstime * MS_PER_TICK);
  1437. X    return TCL_OK;
  1438. X}
  1439. X
  1440. X/*
  1441. X *----------------------------------------------------------------------
  1442. X *
  1443. X * Tcl_UmaskCmd --
  1444. X *     Implements the TCL umask command:
  1445. X *     umask [octalmask]
  1446. X *
  1447. X * Results:
  1448. X *  Standard TCL results, may return the UNIX system error message.
  1449. X *
  1450. X *----------------------------------------------------------------------
  1451. X */
  1452. Xint
  1453. XTcl_UmaskCmd (clientData, interp, argc, argv)
  1454. X    ClientData  clientData;
  1455. X    Tcl_Interp *interp;
  1456. X    int         argc;
  1457. X    char      **argv;
  1458. X{
  1459. X    int mask;
  1460. X
  1461. X    if ((argc < 1) || (argc > 2)) {
  1462. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " octalmask",
  1463. X                          (char *) NULL);
  1464. X        return TCL_ERROR;
  1465. X    }
  1466. X
  1467. X    if (argc == 1) {
  1468. X        mask = umask (0);  /* Get current mask      */
  1469. X        umask (mask);      /* Now set it back (yuk) */
  1470. X        sprintf (interp->result, "%o", mask);
  1471. X    } else {
  1472. X        if (!Tcl_StrToInt (argv[1], 8, &mask)) {
  1473. X            Tcl_AppendResult (interp, "Expected octal number got: ", argv[1],
  1474. X                              (char *) NULL);
  1475. X            return TCL_ERROR;
  1476. X        }
  1477. X
  1478. X        umask(mask);
  1479. X    }
  1480. X
  1481. X    return TCL_OK;
  1482. X}
  1483. X
  1484. X/*
  1485. X *----------------------------------------------------------------------
  1486. X *
  1487. X * Tcl_LinkCmd --
  1488. X *     Implements the TCL unlink command:
  1489. X *         link srcpath destpath
  1490. X *
  1491. X * Results:
  1492. X *  Standard TCL results, may return the UNIX system error message.
  1493. X *
  1494. X *----------------------------------------------------------------------
  1495. X */
  1496. Xint
  1497. XTcl_LinkCmd (clientData, interp, argc, argv)
  1498. X    ClientData  clientData;
  1499. X    Tcl_Interp *interp;
  1500. X    int         argc;
  1501. X    char      **argv;
  1502. X{
  1503. X
  1504. X    if (argc != 3) {
  1505. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1506. X                          " srcpath destpath", (char *) NULL);
  1507. X        return TCL_ERROR;
  1508. X    }
  1509. X    if (link (argv [1], argv [2]) != 0) {
  1510. X       Tcl_AppendResult (interp, argv [0], ": ", Tcl_UnixError (interp),
  1511. X                        (char *) NULL);
  1512. X       return TCL_ERROR;
  1513. X    }
  1514. X
  1515. X    return TCL_OK;
  1516. X}
  1517. X
  1518. X/*
  1519. X *----------------------------------------------------------------------
  1520. X *
  1521. X * Tcl_UnlinkCmd --
  1522. X *     Implements the TCL unlink command:
  1523. X *         unlink fileList
  1524. X *
  1525. X * Results:
  1526. X *  Standard TCL results, may return the UNIX system error message.
  1527. X *
  1528. X *----------------------------------------------------------------------
  1529. X */
  1530. Xint
  1531. XTcl_UnlinkCmd (clientData, interp, argc, argv)
  1532. X    ClientData  clientData;
  1533. X    Tcl_Interp *interp;
  1534. X    int         argc;
  1535. X    char      **argv;
  1536. X{
  1537. X    int    idx, fileArgc, result = TCL_ERROR;
  1538. X    char **fileArgv;
  1539. X
  1540. X    if (argc != 2) {
  1541. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1542. X                          " filelist", (char *) NULL);
  1543. X        return TCL_ERROR;
  1544. X    }
  1545. X    if (Tcl_SplitList (interp, argv [1], &fileArgc, &fileArgv) != TCL_OK)
  1546. X        return TCL_ERROR;
  1547. X
  1548. X    for (idx = 0; idx < fileArgc; idx++) {
  1549. X        if (unlink (fileArgv [idx]) != 0) {
  1550. X           Tcl_AppendResult (interp, argv [0], ": ", fileArgv [idx], ": ",
  1551. X                             Tcl_UnixError (interp), (char *) NULL);
  1552. X           goto exitPoint;
  1553. X        }
  1554. X    }
  1555. X
  1556. X    result = TCL_OK;
  1557. XexitPoint:
  1558. X    ckfree ((char *) fileArgv);
  1559. X    return result;
  1560. X}
  1561. X
  1562. X/*
  1563. X *----------------------------------------------------------------------
  1564. X *
  1565. X * Tcl_MkdirCmd --
  1566. X *     Implements the TCL Mkdir command:
  1567. X *         mkdir [-path] dirList
  1568. X *
  1569. X * Results:
  1570. X *  Standard TCL results, may return the UNIX system error message.
  1571. X *
  1572. X *----------------------------------------------------------------------
  1573. X */
  1574. Xint
  1575. XTcl_MkdirCmd (clientData, interp, argc, argv)
  1576. X    ClientData  clientData;
  1577. X    Tcl_Interp *interp;
  1578. X    int         argc;
  1579. X    char      **argv;
  1580. X{
  1581. X    int           idx, dirArgc, result;
  1582. X    char        **dirArgv, *scanPtr;
  1583. X    struct stat   statBuf;
  1584. X
  1585. X    if ((argc < 2) || (argc > 3))
  1586. X        goto usageError;
  1587. X    if ((argc == 3) && !STREQU (argv [1], "-path"))
  1588. X        goto usageError;
  1589. X
  1590. X    if (Tcl_SplitList (interp, argv [argc - 1], &dirArgc, &dirArgv) != TCL_OK)
  1591. X        return TCL_ERROR;
  1592. X    /*
  1593. X     * Make all the directories, optionally making directories along the path.
  1594. X     */
  1595. X
  1596. X    for (idx = 0; idx < dirArgc; idx++) {
  1597. X        /*
  1598. X         * Make leading directories, if requested.
  1599. X         */
  1600. X        if (argc == 3) {
  1601. X            scanPtr = dirArgv [idx];
  1602. X            result = 0;  /* Start out ok, for dirs that are skipped */
  1603. X
  1604. X            while (*scanPtr != '\0') {
  1605. X                scanPtr = strchr (scanPtr+1, '/');
  1606. X                if ((scanPtr == NULL) || (*(scanPtr+1) == '\0'))
  1607. X                    break;
  1608. X                *scanPtr = '\0';
  1609. X                if (stat (dirArgv [idx], &statBuf) < 0)
  1610. X                    result = mkdir (dirArgv [idx], S_IFDIR | 0777, 0);
  1611. X                *scanPtr = '/';
  1612. X                if (result < 0)
  1613. X                   goto mkdirError;
  1614. X            }
  1615. X        }
  1616. X        /*
  1617. X         * Make final directory in the path.
  1618. X         */
  1619. X        if (mkdir (dirArgv [idx], S_IFDIR | 0777, 0) != 0)
  1620. X           goto mkdirError;
  1621. X    }
  1622. X
  1623. X    ckfree ((char *) dirArgv);
  1624. X    return TCL_OK;
  1625. X
  1626. XmkdirError:
  1627. X    Tcl_AppendResult (interp, argv [0], ": ", dirArgv [idx], ": ",
  1628. X                      Tcl_UnixError (interp), (char *) NULL);
  1629. X    ckfree ((char *) dirArgv);
  1630. X    return TCL_ERROR;
  1631. X
  1632. XusageError:
  1633. X    Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1634. X                      " [-path] dirlist", (char *) NULL);
  1635. X    return TCL_ERROR;
  1636. X}
  1637. X
  1638. X/*
  1639. X *----------------------------------------------------------------------
  1640. X *
  1641. X * Tcl_RmdirCmd --
  1642. X *     Implements the TCL Rmdir command:
  1643. X *         rmdir dirList
  1644. X *
  1645. X * Results:
  1646. X *  Standard TCL results, may return the UNIX system error message.
  1647. X *
  1648. X *----------------------------------------------------------------------
  1649. X */
  1650. Xint
  1651. XTcl_RmdirCmd (clientData, interp, argc, argv)
  1652. X    ClientData  clientData;
  1653. X    Tcl_Interp *interp;
  1654. X    int         argc;
  1655. X    char      **argv;
  1656. X{
  1657. X    int    idx, dirArgc, result = TCL_ERROR;
  1658. X    char **dirArgv;
  1659. X
  1660. X    if (argc != 2) {
  1661. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], 
  1662. X                          " dirlist", (char *) NULL);
  1663. X        return TCL_ERROR;
  1664. X    }
  1665. X    if (Tcl_SplitList (interp, argv [1], &dirArgc, &dirArgv) != TCL_OK)
  1666. X        return TCL_ERROR;
  1667. X
  1668. X    for (idx = 0; idx < dirArgc; idx++) {
  1669. X        if (rmdir (dirArgv [idx]) != 0) {
  1670. X           Tcl_AppendResult (interp, argv [0], ": ", dirArgv [idx], ": ",
  1671. X                             Tcl_UnixError (interp), (char *) NULL);
  1672. X           goto exitPoint;
  1673. X        }
  1674. X    }
  1675. X
  1676. X    result = TCL_OK;
  1677. XexitPoint:
  1678. X    ckfree ((char *) dirArgv);
  1679. X    return result;
  1680. X}
  1681. X
  1682. X/*
  1683. X *----------------------------------------------------------------------
  1684. X *
  1685. X * Tcl_WaitCmd --
  1686. X *     Implements the TCL wait command:
  1687. X *     wait proclist
  1688. X *
  1689. X * Results:
  1690. X *  Standard TCL results, may return the UNIX system error message.
  1691. X *
  1692. X *----------------------------------------------------------------------
  1693. X */
  1694. Xint
  1695. XTcl_WaitCmd (clientData, interp, argc, argv)
  1696. X    ClientData  clientData;
  1697. X    Tcl_Interp *interp;
  1698. X    int         argc;
  1699. X    char      **argv;
  1700. X{
  1701. X    int    waitPid, status, idx, procArgc, result = TCL_ERROR;
  1702. X    char **procArgv;
  1703. X    int   *procIdList;
  1704. X
  1705. X    if (argc != 2) {
  1706. X        Tcl_AppendResult (interp, "wrong # args: ", argv [0], " proclist", 
  1707. X                          (char *) NULL);
  1708. X        return TCL_ERROR;
  1709. X    }
  1710. X
  1711. X    if (Tcl_SplitList (interp, argv [1], &procArgc, &procArgv) != TCL_OK)
  1712. X        return TCL_ERROR;
  1713. X
  1714. X    procIdList = (int *) ckalloc (procArgc * (sizeof (int)));
  1715. X
  1716. X    for (idx = 0; idx < procArgc; idx++) {
  1717. X        if (Tcl_GetInt (interp, procArgv [idx], &procIdList [idx]) != TCL_OK)
  1718. X            goto exitPoint;
  1719. X    }
  1720. X
  1721. X    waitPid = Tcl_WaitPids (procArgc, procIdList, &status);
  1722. X
  1723. X    if (waitPid < 0) {
  1724. X        Tcl_AppendResult (interp, argv [0], ": ", Tcl_UnixError (interp),
  1725. X                          (char *) NULL);
  1726. X        return TCL_ERROR;
  1727. X    }
  1728. X    
  1729. X    if (WIFEXITED (status))
  1730. X        sprintf (interp->result, "%d %s %d", waitPid, "EXIT", 
  1731. X                 WEXITSTATUS (status));
  1732. X    else if (WIFSIGNALED (status))
  1733. X        sprintf (interp->result, "%d %s %s", waitPid, "SIG", 
  1734. X                 Tcl_SignalId (WTERMSIG (status)));
  1735. X    else if (WIFSTOPPED (status))
  1736. X        sprintf (interp->result, "%d %s %s", waitPid, "STOP", 
  1737. X                 Tcl_SignalId (WSTOPSIG (status)));
  1738. X
  1739. X    result = TCL_OK;
  1740. XexitPoint:
  1741. X    ckfree ((char *) procArgv);
  1742. X    ckfree ((char *) procIdList);
  1743. X    return result;
  1744. X}
  1745. END_OF_FILE
  1746. if test 16058 -ne `wc -c <'extended/src/unixcmds.c'`; then
  1747.     echo shar: \"'extended/src/unixcmds.c'\" unpacked with wrong size!
  1748. fi
  1749. # end of 'extended/src/unixcmds.c'
  1750. fi
  1751. echo shar: End of archive 17 \(of 23\).
  1752. cp /dev/null ark17isdone
  1753. MISSING=""
  1754. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  1755.     if test ! -f ark${I}isdone ; then
  1756.     MISSING="${MISSING} ${I}"
  1757.     fi
  1758. done
  1759. if test "${MISSING}" = "" ; then
  1760.     echo You have unpacked all 23 archives.
  1761.     echo "Now cd to "extended", edit the makefile, then do a "make""
  1762.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1763. else
  1764.     echo You still need to unpack the following archives:
  1765.     echo "        " ${MISSING}
  1766. fi
  1767. ##  End of shell archive.
  1768. exit 0
  1769.  
  1770. exit 0 # Just in case...
  1771. -- 
  1772. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1773. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1774. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1775. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1776.