RTS.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /** This is part of the body of the GPCP runtime support.
  2. *
  3. * Written November 1998, John Gough.
  4. *
  5. * CP*rts contains the runtime helpers, this class has
  6. * adapters for hooking into the various Native libraries.
  7. * These are the user accessible parts of the runtime. The
  8. * facilities in CP*rts are known to each code-emitter, but
  9. * have no CP-accessible functions. The interface to the
  10. * user-accessible functions are defined in RTS.cp, and the
  11. * code is defined in this file.
  12. *
  13. * Version of 29 March 2000 (kjg) --
  14. * There is a swindle involved here, for the bootstrap version
  15. * of the compiler: any functions with OUT scalars will have
  16. * a different signature in the old and new versions. This
  17. * module implements both, by overloading the methods.
  18. *
  19. * Version of October 2011 -- JVM version brought into line
  20. * with the CP definition used by the current .NET version.
  21. * Only the required methods are defined, the bootstrap
  22. * versions have been removed.
  23. */
  24. package CP.RTS;
  25. import java.io.*;
  26. import CP.CPJ.*;
  27. import CP.CPJrts.*;
  28. import java.text.NumberFormat;
  29. /* ------------------------------------------------------------ */
  30. /* Support for RTS.cp */
  31. /* ------------------------------------------------------------ */
  32. /* The text of RTS.cp is interleaved here to associate the */
  33. /* java with the promises of the Component Pascal source. */
  34. /* ------------------------------------------------------------ */
  35. //
  36. // SYSTEM MODULE RTS;
  37. public final class RTS
  38. {
  39. /* Some Initializations ... */
  40. private static NumberFormat localFormat = NumberFormat.getInstance();
  41. //
  42. // VAR defaultTarget- : ARRAY 4 OF CHAR;
  43. // fltNegInfinity- : SHORTREAL;
  44. // fltPosInfinity- : SHORTREAL;
  45. // dblNegInfinity- : REAL;
  46. // dblPosInfinity- : REAL;
  47. public static char[] defaultTarget = {'j','v','m','\0'};
  48. public static float fltNegInfinity = Float.NEGATIVE_INFINITY;
  49. public static float fltPosInfinity = Float.POSITIVE_INFINITY;
  50. public static double dblNegInfinity = Double.NEGATIVE_INFINITY;
  51. public static double dblPosInfinity = Double.POSITIVE_INFINITY;
  52. //
  53. // TYPE CharOpen* = POINTER TO ARRAY OF CHAR;
  54. //
  55. // TYPE NativeType* = POINTER TO ABSTRACT RECORD END;
  56. // NativeObject* = POINTER TO ABSTRACT RECORD END;
  57. // NativeString* = POINTER TO RECORD END;
  58. // NativeException*= POINTER TO EXTENSIBLE RECORD END;
  59. //
  60. // VAR eol- : POINTER TO ARRAY OF CHAR; (* OS-specific end of line string *)
  61. //
  62. public static char[] eol = { '\n', '\0' };
  63. //
  64. // (* ========================================================== *)
  65. // (* ============= Support for native exceptions ============== *)
  66. // (* ========================================================== *)
  67. // PROCEDURE getStr*(x : NativeException) : CharOpen;
  68. public static char[] getStr(java.lang.Exception x) {
  69. String str = x.toString();
  70. return CPJrts.JavaStrToChrOpen(str);
  71. }
  72. //
  73. // --------------------------------------------------------------
  74. // PROCEDURE Throw*(IN s : ARRAY OF CHAR);
  75. // (** Abort execution with an error *)
  76. public static void Throw(char[] s) throws Exception {
  77. throw new Exception(new String(s));
  78. }
  79. /* ------------------------------------------------------------ */
  80. // PROCEDURE TypeName*(str : NativeType) : CharOpen;
  81. // (* Get the character at zero-based index idx *)
  82. //
  83. public static char[] TypeName(java.lang.Class t) {
  84. return CPJrts.JavaStrToChrOpen(t.getSimpleName());
  85. }
  86. /* ------------------------------------------------------------ */
  87. // PROCEDURE CharAtIndex*(str : NativeString; idx : INTEGER) : CHAR;
  88. // (* Get the character at zero-based index idx *)
  89. //
  90. public static char CharAtIndex( String s, int i ) { return s.charAt(i); }
  91. /* ------------------------------------------------------------ */
  92. // PROCEDURE Length*(str : NativeString) : INTEGER;
  93. // (* Get the length of the native string *)
  94. //
  95. public static int Length( String s ) { return s.length(); }
  96. //
  97. // (* ========================================================== *)
  98. // (* ============= Conversions FROM array of char ============= *)
  99. // (* ========================================================== *)
  100. // PROCEDURE StrToBool*(IN s : ARRAY OF CHAR; OUT b : BOOLEAN; OUT ok : BOOLEAN);
  101. // (** Parse array into a BOOLEAN TRUE/FALSE *)
  102. //
  103. public static boolean StrToBool(char[] str,
  104. boolean[] r) // OUT param
  105. {
  106. try {
  107. r[0] = true;
  108. return Boolean.parseBoolean(CPJ.MkStr(str));
  109. } catch(Exception e) {
  110. r[0] = false;
  111. return false;
  112. }
  113. }
  114. //
  115. // --------------------------------------------------------------
  116. // PROCEDURE StrToByte*(IN s : ARRAY OF CHAR; OUT b : BYTE; OUT ok : BOOLEAN);
  117. // (** Parse array into a BYTE integer (unsigned byte in CP *)
  118. //
  119. public static byte StrToByte(char[] str,
  120. boolean[] r) // OUT param
  121. {
  122. try {
  123. r[0] = true;
  124. int value = Integer.parseInt(CPJ.MkStr(str));
  125. if (value >= -128 && value < 128)
  126. return (byte)value;
  127. } catch(Exception e) {
  128. }
  129. r[0] = false;
  130. return 0;
  131. }
  132. //
  133. // --------------------------------------------------------------
  134. // PROCEDURE StrToUByte*(IN s : ARRAY OF CHAR; OUT b : BYTE; OUT ok : BOOLEAN);
  135. // (** Parse array into a BYTE integer *)
  136. //
  137. public static byte StrToUByte(char[] str,
  138. boolean[] r) // OUT param
  139. {
  140. try {
  141. r[0] = true;
  142. int value = Integer.parseInt(CPJ.MkStr(str));
  143. if (value >= 0 && value < 256)
  144. return (byte)value;
  145. } catch(Exception e) {
  146. }
  147. r[0] = false;
  148. return 0;
  149. }
  150. //
  151. // --------------------------------------------------------------
  152. // PROCEDURE StrToShort*(IN s : ARRAY OF CHAR; OUT si : SHORTINT; OUT ok : BOOLEAN);
  153. // (** Parse an array into a CP SHORTINT *)
  154. //
  155. public static short StrToShort(char[] str,
  156. boolean[] r) // OUT param
  157. {
  158. try {
  159. r[0] = true;
  160. int value = Integer.parseInt(CPJ.MkStr(str));
  161. if (value >= -0x8000 && value < 0x7fff)
  162. return (short)value;
  163. } catch(Exception e) {
  164. }
  165. r[0] = false;
  166. return 0;
  167. }
  168. //
  169. // --------------------------------------------------------------
  170. // PROCEDURE StrToUShort*(IN s:ARRAY OF CHAR; OUT si:SHORTINT; OUT ok:BOOLEAN);
  171. // (** Parse an array into a CP Unsigned SHORTINT *)
  172. //
  173. public static short StrToUShort(char[] str,
  174. boolean[] r) // OUT param
  175. {
  176. try {
  177. r[0] = true;
  178. int value = Integer.parseInt(CPJ.MkStr(str));
  179. if (value > 0 && value < 0xffff)
  180. return (short)value;
  181. } catch(Exception e) {
  182. }
  183. r[0] = false;
  184. return 0;
  185. }
  186. //
  187. // --------------------------------------------------------------
  188. // PROCEDURE StrToInt*(IN s:ARRAY OF CHAR; OUT i:INTEGER; OUT ok:BOOLEAN);
  189. // (** Parse an array into a CP INTEGER *)
  190. // (* Note that first OUT or VAR scalar becomes return value if a pure procedure *)
  191. //
  192. public static int StrToInt(char[] str,
  193. boolean[] r) // OUT param
  194. {
  195. try {
  196. r[0] = true;
  197. return Integer.parseInt(CPJ.MkStr(str));
  198. } catch(Exception e) {
  199. r[0] = false;
  200. return 0;
  201. }
  202. }
  203. //
  204. // --------------------------------------------------------------
  205. // PROCEDURE StrToUInt*(IN s:ARRAY OF CHAR; OUT i:INTEGER; OUT ok:BOOLEAN);
  206. // (** Parse an array into a CP INTEGER *)
  207. //
  208. public static int StrToUInt(char[] str,
  209. boolean[] r) // OUT param
  210. {
  211. try {
  212. r[0] = true;
  213. long value = Long.parseLong(CPJ.MkStr(str));
  214. if (value > 0 && value < 0xffffffff)
  215. return (int)value;
  216. } catch(Exception e) {
  217. }
  218. r[0] = false;
  219. return 0;
  220. }
  221. //
  222. // --------------------------------------------------------------
  223. // PROCEDURE StrToLong*(IN s:ARRAY OF CHAR; OUT i:LONGINT; OUT ok:BOOLEAN);
  224. // (** Parse an array into a CP LONGINT *)
  225. //
  226. public static long StrToLong(char[] str,
  227. boolean[] r) // OUT param
  228. {
  229. try {
  230. r[0] = true;
  231. return Long.parseLong(CPJ.MkStr(str));
  232. } catch(Exception e) {
  233. r[0] = false;
  234. return 0;
  235. }
  236. }
  237. //
  238. // --------------------------------------------------------------
  239. // PROCEDURE StrToULong*(IN s:ARRAY OF CHAR; OUT i:LONGINT; OUT ok:BOOLEAN);
  240. // (** Parse an array into a CP LONGINT *)
  241. //
  242. // Throw method not found exception.
  243. //
  244. // --------------------------------------------------------------
  245. // PROCEDURE HexStrToUByte*(IN s:ARRAY OF CHAR; OUT b:BYTE; OUT ok:BOOLEAN);
  246. // (** Parse hexadecimal array into a BYTE integer *)
  247. //
  248. public static byte HexStrToUByte(char[] str,
  249. boolean[] r) // OUT param
  250. {
  251. try {
  252. r[0] = true;
  253. return Byte.decode(CPJ.MkStr(str)).byteValue();
  254. } catch(Exception e) {
  255. r[0] = false;
  256. return 0;
  257. }
  258. }
  259. //
  260. // (* ------------------- Low-level String Conversions -------------------- *)
  261. // (* Three versions for different cultures. *Invar uses invariant culture *)
  262. // (* *Local uses current locale *)
  263. // (* StrToReal & RealToStr do not behave the same on JVM and CLR. *)
  264. // (* They are provided for compatability with versions < 1.3.1 *)
  265. // (* ------------------- Low-level String Conversions -------------------- *)
  266. //
  267. // PROCEDURE StrToReal*(IN s : ARRAY OF CHAR;
  268. // OUT r : REAL;
  269. // OUT ok : BOOLEAN);
  270. // (** Parse array into an ieee double REAL *)
  271. //
  272. public static double StrToReal(char[] str,
  273. boolean[] r) // OUT param
  274. {
  275. try {
  276. r[0] = true;
  277. return Double.valueOf(CPJ.MkStr(str)).doubleValue();
  278. } catch(Exception e) {
  279. r[0] = false;
  280. return 0.0;
  281. }
  282. }
  283. //
  284. // --------------------------------------------------------------
  285. // PROCEDURE StrToRealInvar*(IN s : ARRAY OF CHAR;
  286. // OUT r : REAL;
  287. // OUT ok : BOOLEAN);
  288. // (** Parse array using invariant culture, into an ieee double REAL *)
  289. //
  290. public static double StrToRealInvar(char[] str,
  291. boolean[] r) // OUT param
  292. {
  293. try {
  294. r[0] = true;
  295. return Double.valueOf(CPJ.MkStr(str)).doubleValue();
  296. } catch(Exception e) {
  297. r[0] = false;
  298. return 0.0;
  299. }
  300. }
  301. //
  302. // --------------------------------------------------------------
  303. // PROCEDURE StrToRealLocal*(IN s : ARRAY OF CHAR;
  304. // OUT r : REAL;
  305. // OUT ok : BOOLEAN);
  306. // (** Parse array using current locale, into an ieee double REAL *)
  307. //
  308. public static double StrToRealLocal(char[] str,
  309. boolean[] r) // OUT param
  310. {
  311. try {
  312. r[0] = true;
  313. return localFormat.parse(CPJ.MkStr(str)).doubleValue();
  314. } catch(Exception e) {
  315. r[0] = false;
  316. return 0.0;
  317. }
  318. }
  319. //
  320. // --------------------------------------------------------------
  321. // PROCEDURE StrToSReal*(IN s : ARRAY OF CHAR;
  322. // OUT r : SHORTREAL;
  323. // OUT ok : BOOLEAN);
  324. //
  325. public static float StrToSReal(char[] str,
  326. boolean[] r) // OUT param
  327. {
  328. try {
  329. r[0] = true;
  330. return Float.valueOf(CPJ.MkStr(str)).floatValue();
  331. } catch(Exception e) {
  332. r[0] = false;
  333. return 0.0F;
  334. }
  335. }
  336. //
  337. // --------------------------------------------------------------
  338. // PROCEDURE StrToSRealInvar*(IN s : ARRAY OF CHAR;
  339. // OUT r : SHORTREAL;
  340. // OUT ok : BOOLEAN);
  341. //
  342. public static float StrToSRealInvar(char[] str,
  343. boolean[] r) // OUT param
  344. {
  345. try {
  346. r[0] = true;
  347. return Float.valueOf(CPJ.MkStr(str)).floatValue();
  348. } catch(Exception e) {
  349. r[0] = false;
  350. return 0.0F;
  351. }
  352. }
  353. //
  354. // --------------------------------------------------------------
  355. // PROCEDURE StrToSRealLocal*(IN s : ARRAY OF CHAR;
  356. // OUT r : SHORTREAL;
  357. // OUT ok : BOOLEAN);
  358. // (** Parse array into a short REAL *)
  359. //
  360. public static float StrToSRealLocal(char[] str,
  361. boolean[] r) // OUT param
  362. {
  363. try {
  364. r[0] = true;
  365. return localFormat.parse(CPJ.MkStr(str)).floatValue();
  366. } catch(Exception e) {
  367. r[0] = false;
  368. return 0.0F;
  369. }
  370. }
  371. //
  372. // (* ========================================================== *)
  373. // (* ============== Conversions TO array of char ============== *)
  374. // (* ========================================================== *)
  375. // PROCEDURE RealToStr*(r : REAL; OUT s : ARRAY OF CHAR);
  376. // (** Decode a CP REAL into an array *)
  377. //
  378. public static void RealToStr(double num,
  379. char[] str)
  380. {
  381. String jls = String.valueOf(num);
  382. int len = jls.length();
  383. if (len >= str.length)
  384. len = str.length - 1;
  385. jls.getChars(0, len, str, 0);
  386. str[len] = '\0';
  387. }
  388. //
  389. // --------------------------------------------------------------
  390. // PROCEDURE RealToStrInvar*(r : REAL; OUT s : ARRAY OF CHAR);
  391. // (** Decode a CP REAL into an array in invariant culture *)
  392. //
  393. public static void RealToStrInvar(double num,
  394. char[] str)
  395. {
  396. String jls = String.valueOf(num);
  397. int len = jls.length();
  398. if (len >= str.length)
  399. len = str.length - 1;
  400. jls.getChars(0, len, str, 0);
  401. str[len] = '\0';
  402. }
  403. //
  404. // --------------------------------------------------------------
  405. // PROCEDURE RealToStrLocal*(r : REAL; OUT s : ARRAY OF CHAR);
  406. // (** Decode a CP REAL into an array in the current locale *)
  407. //
  408. public static void RealToStrLocal(double num,
  409. char[] str)
  410. {
  411. String jls = localFormat.format(num);
  412. int len = jls.length();
  413. if (len >= str.length)
  414. len = str.length - 1;
  415. jls.getChars(0, len, str, 0);
  416. str[len] = '\0';
  417. }
  418. //
  419. // --------------------------------------------------------------
  420. // PROCEDURE SRealToStr*(r : SHORTREAL; OUT s : ARRAY OF CHAR);
  421. //
  422. public static void SRealToStr(float num,
  423. char[] str)
  424. {
  425. String jls = Float.toString(num);
  426. int len = jls.length();
  427. if (len >= str.length)
  428. len = str.length - 1;
  429. jls.getChars(0, len, str, 0);
  430. str[len] = '\0';
  431. }
  432. //
  433. // --------------------------------------------------------------
  434. // PROCEDURE SRealToStrInvar*(r : SHORTREAL; OUT s : ARRAY OF CHAR);
  435. //
  436. public static void SRealToStrInvar(float num,
  437. char[] str)
  438. {
  439. String jls = Float.toString(num);
  440. int len = jls.length();
  441. if (len >= str.length)
  442. len = str.length - 1;
  443. jls.getChars(0, len, str, 0);
  444. str[len] = '\0';
  445. }
  446. //
  447. // --------------------------------------------------------------
  448. // PROCEDURE SRealToStrLocal*(r : SHORTREAL; OUT s : ARRAY OF CHAR);
  449. // (** Decode a CP SHORTREAL into an array *)
  450. //
  451. public static void SRealToStrLocal(float num,
  452. char[] str)
  453. {
  454. String jls = localFormat.format(num);
  455. int len = jls.length();
  456. if (len >= str.length)
  457. len = str.length - 1;
  458. jls.getChars(0, len, str, 0);
  459. str[len] = '\0';
  460. }
  461. //
  462. // --------------------------------------------------------------
  463. // PROCEDURE IntToStr*(i : INTEGER; OUT s : ARRAY OF CHAR);
  464. // (** Decode a CP INTEGER into an array *)
  465. //
  466. public static void IntToStr(int num,
  467. char[] str)
  468. {
  469. String jls = String.valueOf(num);
  470. int len = jls.length();
  471. if (len >= str.length)
  472. len = str.length - 1;
  473. jls.getChars(0, len, str, 0);
  474. str[len] = '\0';
  475. }
  476. //
  477. // --------------------------------------------------------------
  478. // PROCEDURE ObjToStr*(obj : ANYPTR; OUT s : ARRAY OF CHAR);
  479. // (** Decode a CP INTEGER into an array *)
  480. //
  481. public static void ObjToStr(Object obj, char[] str) {
  482. CPJ.MkArr(obj.getClass().getName(), str);
  483. }
  484. //
  485. // --------------------------------------------------------------
  486. // PROCEDURE LongToStr*(i : LONGINT; OUT s : ARRAY OF CHAR);
  487. // (** Decode a CP INTEGER into an array *)
  488. //
  489. public static void LongToStr(long num,
  490. char[] str)
  491. {
  492. String jls = String.valueOf(num);
  493. int len = jls.length();
  494. if (len >= str.length)
  495. len = str.length - 1;
  496. jls.getChars(0, len, str, 0);
  497. str[len] = '\0';
  498. }
  499. //
  500. // (* ========================================================== *)
  501. // (* ========== Casts with no representation change =========== *)
  502. // (* ========================================================== *)
  503. // PROCEDURE realToLongBits*(r : REAL) : LONGINT;
  504. // (** Convert an ieee double into a longint with same bit pattern *)
  505. //
  506. public static long realToLongBits(double r) {
  507. return java.lang.Double.doubleToLongBits(r);
  508. }
  509. //
  510. // --------------------------------------------------------------
  511. // PROCEDURE longBitsToReal*(l : LONGINT) : REAL;
  512. // (** Convert an ieee double into a longint with same bit pattern *)
  513. //
  514. public static double longBitsToReal(long l) {
  515. return java.lang.Double.longBitsToDouble(l);
  516. }
  517. //
  518. // --------------------------------------------------------------
  519. // PROCEDURE shortRealToIntBits*(r : SHORTREAL) : INTEGER;
  520. // (** Convert an ieee float into an int with same bit pattern *)
  521. //
  522. public static int shortRealToIntBits(float f) {
  523. return Float.floatToIntBits(f);
  524. }
  525. //
  526. // --------------------------------------------------------------
  527. // PROCEDURE intBitsToShortReal*(i : INTEGER) : SHORTREAL;
  528. // (** Convert an int into an ieee float with same bit pattern *)
  529. //
  530. public static float intBitsToShortReal(int i) {
  531. return Float.intBitsToFloat(i);
  532. }
  533. //
  534. // --------------------------------------------------------------
  535. // PROCEDURE hiByte*(i : SHORTINT) : BYTE;
  536. // (** Get hi-significant word of short *)
  537. //
  538. public static byte hiByte(short s) {
  539. return (byte) (s >> 8);
  540. }
  541. //
  542. // --------------------------------------------------------------
  543. // PROCEDURE loByte*(i : SHORTINT) : BYTE;
  544. // (** Get lo-significant word of short *)
  545. //
  546. public static byte loByte(short s) {
  547. return (byte) s;
  548. }
  549. //
  550. // --------------------------------------------------------------
  551. // PROCEDURE hiShort*(i : INTEGER) : SHORTINT;
  552. // (** Get hi-significant word of integer *)
  553. //
  554. public static short hiShort(int i) {
  555. return (short) (i >> 16);
  556. }
  557. //
  558. // --------------------------------------------------------------
  559. // PROCEDURE loShort*(i : INTEGER) : SHORTINT;
  560. // (** Get lo-significant word of integer *)
  561. //
  562. public static short loShort(int i) {
  563. return (short) i;
  564. }
  565. //
  566. // --------------------------------------------------------------
  567. // PROCEDURE hiInt*(l : LONGINT) : INTEGER;
  568. // (** Get hi-significant word of long integer *)
  569. //
  570. public static int hiInt(long l) {
  571. return (int) (l >> 32);
  572. }
  573. //
  574. // --------------------------------------------------------------
  575. // PROCEDURE loInt*(l : LONGINT) : INTEGER;
  576. // (** Get lo-significant word of long integer *)
  577. //
  578. public static int loInt(long l) {
  579. return (int) l;
  580. }
  581. //
  582. // (* ========================================================== *)
  583. // (* ============= Various utility procedures ================= *)
  584. // (* ========================================================== *)
  585. //
  586. // PROCEDURE GetMillis*() : LONGINT;
  587. // (** Get time in milliseconds *)
  588. public static long GetMillis() {
  589. return System.currentTimeMillis();
  590. }
  591. //
  592. // --------------------------------------------------------------
  593. // PROCEDURE GetDateString*(OUT str : ARRAY OF CHAR);
  594. // (** Get a date string in some native format *)
  595. //
  596. public static void GetDateString(char[] str) {
  597. String date = new java.util.Date().toString();
  598. int len = date.length();
  599. date.getChars(0, len, str, 0);
  600. str[len] = '\0';
  601. }
  602. //
  603. // --------------------------------------------------------------
  604. // PROCEDURE ClassMarker*(o : ANYPTR);
  605. // (** Write class name to standard output *)
  606. //
  607. public static void ClassMarker(Object o) {
  608. System.out.print(o.getClass().getName());
  609. }
  610. //
  611. // END RTS.
  612. /* ------------------------------------------------------------ */
  613. /* ------------------------------------------------------------ */
  614. /* ------------------------------------------------------------ */
  615. }