home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR2 / DVPG30FS.ZIP / JMEMDOS.C < prev    next >
C/C++ Source or Header  |  1993-02-19  |  19KB  |  635 lines

  1. /*
  2.  * jmemdos.c  (jmemsys.c)
  3.  *
  4.  * Copyright (C) 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file provides an MS-DOS-compatible implementation of the system-
  9.  * dependent portion of the JPEG memory manager.  Temporary data can be
  10.  * stored in extended or expanded memory as well as in regular DOS files.
  11.  *
  12.  * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
  13.  * if you compile in a small-data memory model; it should NOT be defined if
  14.  * you use a large-data memory model.  This file is not recommended if you
  15.  * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
  16.  * Also, this code will NOT work if struct fields are aligned on greater than
  17.  * 2-byte boundaries.
  18.  *
  19.  * Based on code contributed by Ge' Weijers.
  20.  */
  21.  
  22. /*
  23.  * If you have both extended and expanded memory, you may want to change the
  24.  * order in which they are tried in jopen_backing_store.  On a 286 machine
  25.  * expanded memory is usually faster, since extended memory access involves
  26.  * an expensive protected-mode-and-back switch.  On 386 and better, extended
  27.  * memory is usually faster.  As distributed, the code tries extended memory
  28.  * first (what? not everyone has a 386? :-).
  29.  *
  30.  * You can disable use of extended/expanded memory entirely by altering these
  31.  * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
  32.  */
  33.  
  34. #ifndef XMS_SUPPORTED
  35. #define XMS_SUPPORTED  1
  36. #endif
  37. #ifndef EMS_SUPPORTED
  38. #define EMS_SUPPORTED  1
  39. #endif
  40.  
  41.  
  42. #include "jinclude.h"
  43. #include "jmemsys.h"
  44.  
  45. #ifdef INCLUDES_ARE_ANSI
  46. #include <stdlib.h>        /* to declare malloc(), free(), getenv() */
  47. #else
  48. extern void * malloc PP((size_t size));
  49. extern void free PP((void *ptr));
  50. extern char * getenv PP((const char * name));
  51. #endif
  52.  
  53. #ifdef NEED_FAR_POINTERS
  54.  
  55. #ifdef __TURBOC__
  56. /* These definitions work for Borland C (Turbo C) */
  57. #include <alloc.h>        /* need farmalloc(), farfree() */
  58. #define far_malloc(x)    farmalloc(x)
  59. #define far_free(x)    farfree(x)
  60. #else
  61. /* These definitions work for Microsoft C and compatible compilers */
  62. #include <malloc.h>        /* need _fmalloc(), _ffree() */
  63. #define far_malloc(x)    _fmalloc(x)
  64. #define far_free(x)    _ffree(x)
  65. #endif
  66.  
  67. #endif
  68.  
  69. #ifdef DONT_USE_B_MODE        /* define mode parameters for fopen() */
  70. #define READ_BINARY    "r"
  71. #else
  72. #define READ_BINARY    "rb"
  73. #endif
  74.  
  75.  
  76. /*
  77.  * Declarations for assembly-language support routines (see jmemdosa.asm).
  78.  *
  79.  * The functions are declared "far" as are all pointer arguments;
  80.  * this ensures the assembly source code will work regardless of the
  81.  * compiler memory model.  We assume "short" is 16 bits, "long" is 32.
  82.  */
  83.  
  84. typedef void far * XMSDRIVER;    /* actually a pointer to code */
  85. typedef struct {        /* registers for calling XMS driver */
  86.     unsigned short ax, dx, bx;
  87.     void far * ds_si;
  88.       } XMScontext;
  89. typedef struct {        /* registers for calling EMS driver */
  90.     unsigned short ax, dx, bx;
  91.     void far * ds_si;
  92.       } EMScontext;
  93.  
  94. EXTERN short far jdos_open PP((short far * handle, char far * filename));
  95. EXTERN short far jdos_close PP((short handle));
  96. EXTERN short far jdos_seek PP((short handle, long offset));
  97. EXTERN short far jdos_read PP((short handle, void far * buffer,
  98.                    unsigned short count));
  99. EXTERN short far jdos_write PP((short handle, void far * buffer,
  100.                 unsigned short count));
  101. EXTERN void far jxms_getdriver PP((XMSDRIVER far *));
  102. EXTERN void far jxms_calldriver PP((XMSDRIVER, XMScontext far *));
  103. EXTERN short far jems_available PP((void));
  104. EXTERN void far jems_calldriver PP((EMScontext far *));
  105.  
  106.  
  107. static external_methods_ptr methods; /* saved for access to error_exit */
  108.  
  109. static long total_used;        /* total FAR memory requested so far */
  110.  
  111.  
  112. /*
  113.  * Selection of a file name for a temporary file.
  114.  * This is highly system-dependent, and you may want to customize it.
  115.  */
  116.  
  117. static int next_file_num;    /* to distinguish among several temp files */
  118.  
  119. LOCAL void
  120. select_file_name (char * fname)
  121. {
  122.   const char * env;
  123.   char * ptr;
  124.   FILE * tfile;
  125.  
  126.   /* Keep generating file names till we find one that's not in use */
  127.   for (;;) {
  128.     /* Get temp directory name from environment TMP or TEMP variable;
  129.      * if none, use "."
  130.      */
  131.     if ((env = (const char *) getenv("TMP")) == NULL)
  132.       if ((env = (const char *) getenv("TEMP")) == NULL)
  133.     env = ".";
  134.     if (*env == '\0')        /* null string means "." */
  135.       env = ".";
  136.     ptr = fname;        /* copy name to fname */
  137.     while (*env != '\0')
  138.       *ptr++ = *env++;
  139.     if (ptr[-1] != '\\' && ptr[-1] != '/')
  140.       *ptr++ = '\\';        /* append backslash if not in env variable */
  141.     /* Append a suitable file name */
  142.     next_file_num++;        /* advance counter */
  143.     sprintf(ptr, "JPG%03d.TMP", next_file_num);
  144.     /* Probe to see if file name is already in use */
  145.     if ((tfile = fopen(fname, READ_BINARY)) == NULL)
  146.       break;
  147.     fclose(tfile);        /* oops, it's there; close tfile & try again */
  148.   }
  149. }
  150.  
  151.  
  152. /*
  153.  * Near-memory allocation and freeing are controlled by the regular library
  154.  * routines malloc() and free().
  155.  */
  156.  
  157. GLOBAL void *
  158. jget_small (size_t sizeofobject)
  159. {
  160.   /* near data space is NOT counted in total_used */
  161. #ifndef NEED_FAR_POINTERS
  162.   total_used += sizeofobject;
  163. #endif
  164.   return (void *) malloc(sizeofobject);
  165. }
  166.  
  167. GLOBAL void
  168. jfree_small (void * object)
  169. {
  170.   free(object);
  171. }
  172.  
  173.  
  174. /*
  175.  * Far-memory allocation and freeing
  176.  */
  177.  
  178. #ifdef NEED_FAR_POINTERS
  179.  
  180. GLOBAL void FAR *
  181. jget_large (size_t sizeofobject)
  182. {
  183.   total_used += sizeofobject;
  184.   return (void FAR *) far_malloc(sizeofobject);
  185. }
  186.  
  187. GLOBAL void
  188. jfree_large (void FAR * object)
  189. {
  190.   far_free(object);
  191. }
  192.  
  193. #endif
  194.  
  195.  
  196. /*
  197.  * This routine computes the total memory space available for allocation.
  198.  * It's impossible to do this in a portable way; our current solution is
  199.  * to make the user tell us (with a default value set at compile time).
  200.  * If you can actually get the available space, it's a good idea to subtract
  201.  * a slop factor of 5% or so.
  202.  */
  203.  
  204. #ifndef DEFAULT_MAX_MEM        /* so can override from makefile */
  205. #define DEFAULT_MAX_MEM        300000L /* for total usage about 450K */
  206. #endif
  207.  
  208. GLOBAL long
  209. jmem_available (long min_bytes_needed, long max_bytes_needed)
  210. {
  211.   return methods->max_memory_to_use - total_used;
  212. }
  213.  
  214.  
  215. /*
  216.  * Backing store (temporary file) management.
  217.  * Backing store objects are only used when the value returned by
  218.  * jmem_available is less than the total space needed.  You can dispense
  219.  * with these routines if you have plenty of virtual memory; see jmemnobs.c.
  220.  */
  221.  
  222. /*
  223.  * For MS-DOS we support three types of backing storage:
  224.  *   1. Conventional DOS files.  We access these by direct DOS calls rather
  225.  *      than via the stdio package.  This provides a bit better performance,
  226.  *      but the real reason is that the buffers to be read or written are FAR.
  227.  *      The stdio library for small-data memory models can't cope with that.
  228.  *   2. Extended memory, accessed per the XMS V2.0 specification.
  229.  *   3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
  230.  * You'll need copies of those specs to make sense of the related code.
  231.  * The specs are available by Internet FTP from SIMTEL20 and its various
  232.  * mirror sites; see microsoft/xms20.arc and info/limems41.zip.
  233.  */
  234.  
  235.  
  236. /*
  237.  * Access methods for a DOS file.
  238.  */
  239.  
  240.  
  241. METHODDEF void
  242. read_file_store (backing_store_ptr info, void FAR * buffer_address,
  243.          long file_offset, long byte_count)
  244. {
  245.   if (jdos_seek(info->handle.file_handle, file_offset))
  246.     ERREXIT(methods, "seek failed on temporary file");
  247.   /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  248.   if (byte_count > 65535L)    /* safety check */
  249.     ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
  250.   if (jdos_read(info->handle.file_handle, buffer_address,
  251.         (unsigned short) byte_count))
  252.     ERREXIT(methods, "read failed on temporary file");
  253. }
  254.  
  255.  
  256. METHODDEF void
  257. write_file_store (backing_store_ptr info, void FAR * buffer_address,
  258.           long file_offset, long byte_count)
  259. {
  260.   if (jdos_seek(info->handle.file_handle, file_offset))
  261.     ERREXIT(methods, "seek failed on temporary file");
  262.   /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
  263.   if (byte_count > 65535L)    /* safety check */
  264.     ERREXIT(methods, "MAX_ALLOC_CHUNK should be less than 64K");
  265.   if (jdos_write(info->handle.file_handle, buffer_address,
  266.          (unsigned short) byte_count))
  267.     ERREXIT(methods, "write failed on temporary file --- out of disk space?");
  268. }
  269.  
  270.  
  271. METHODDEF void
  272. close_file_store (backing_store_ptr info)
  273. {
  274.   jdos_close(info->handle.file_handle);    /* close the file */
  275.   remove(info->temp_name);    /* delete the file */
  276. /* If your system doesn't have remove(), try unlink() instead.
  277.  * remove() is the ANSI-standard name for this function, but
  278.  * unlink() was more common in pre-ANSI systems.
  279.  */
  280.   TRACEMS1(methods, 1, "Closed DOS file %d", info->handle.file_handle);
  281. }
  282.  
  283.  
  284. LOCAL boolean
  285. open_file_store (backing_store_ptr info, long total_bytes_needed)
  286. {
  287.   short handle;
  288.   char tracemsg[TEMP_NAME_LENGTH+40];
  289.  
  290.   select_file_name(info->temp_name);
  291.   if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
  292.     /* hack to get around TRACEMS' inability to handle string parameters */
  293.     sprintf(tracemsg, "Failed to create temporary file %s", info->temp_name);
  294.     ERREXIT(methods, tracemsg);    /* jopen_backing_store will fail anyway */
  295.     return FALSE;
  296.   }
  297.   info->handle.file_handle = handle;
  298.   info->read_backing_store = read_file_store;
  299.   info->write_backing_store = write_file_store;
  300.   info->close_backing_store = close_file_store;
  301.   /* hack to get around TRACEMS' inability to handle string parameters */
  302.   sprintf(tracemsg, "Opened DOS file %d  %s", handle, info->temp_name);
  303.   TRACEMS(methods, 1, tracemsg);
  304.   return TRUE;            /* succeeded */
  305. }
  306.  
  307.  
  308. /*
  309.  * Access methods for extended memory.
  310.  */
  311.  
  312. #if XMS_SUPPORTED
  313.  
  314. static XMSDRIVER xms_driver;    /* saved address of XMS driver */
  315.  
  316. typedef union {            /* either long offset or real-mode pointer */
  317.     long offset;
  318.     void far * ptr;
  319.       } XMSPTR;
  320.  
  321. typedef struct {        /* XMS move specification structure */
  322.     long length;
  323.     XMSH src_handle;
  324.     XMSPTR src;
  325.     XMSH dst_handle;
  326.     XMSPTR dst;
  327.       } XMSspec;
  328.  
  329. #define ODD(X)    (((X) & 1L) != 0)
  330.  
  331.  
  332. METHODDEF void
  333. read_xms_store (backing_store_ptr info, void FAR * buffer_address,
  334.         long file_offset, long byte_count)
  335. {
  336.   XMScontext ctx;
  337.   XMSspec spec;
  338.   char endbuffer[2];
  339.  
  340.   /* The XMS driver can't cope with an odd length, so handle the last byte
  341.    * specially if byte_count is odd.  We don't expect this to be common.
  342.    */
  343.  
  344.   spec.length = byte_count & (~ 1L);
  345.   spec.src_handle = info->handle.xms_handle;
  346.   spec.src.offset = file_offset;
  347.   spec.dst_handle = 0;
  348.   spec.dst.ptr = buffer_address;
  349.   
  350.   ctx.ds_si = (void far *) & spec;
  351.   ctx.ax = 0x0b00;        /* EMB move */
  352.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  353.   if (ctx.ax != 1)
  354.     ERREXIT(methods, "read from extended memory failed");
  355.  
  356.   if (ODD(byte_count)) {
  357.     read_xms_store(info, (void FAR *) endbuffer,
  358.            file_offset + byte_count - 1L, 2L);
  359.     ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
  360.   }
  361. }
  362.  
  363.  
  364. METHODDEF void
  365. write_xms_store (backing_store_ptr info, void FAR * buffer_address,
  366.          long file_offset, long byte_count)
  367. {
  368.   XMScontext ctx;
  369.   XMSspec spec;
  370.   char endbuffer[2];
  371.  
  372.   /* The XMS driver can't cope with an odd length, so handle the last byte
  373.    * specially if byte_count is odd.  We don't expect this to be common.
  374.    */
  375.  
  376.   spec.length = byte_count & (~ 1L);
  377.   spec.src_handle = 0;
  378.   spec.src.ptr = buffer_address;
  379.   spec.dst_handle = info->handle.xms_handle;
  380.   spec.dst.offset = file_offset;
  381.  
  382.   ctx.ds_si = (void far *) & spec;
  383.   ctx.ax = 0x0b00;        /* EMB move */
  384.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  385.   if (ctx.ax != 1)
  386.     ERREXIT(methods, "write to extended memory failed");
  387.  
  388.   if (ODD(byte_count)) {
  389.     read_xms_store(info, (void FAR *) endbuffer,
  390.            file_offset + byte_count - 1L, 2L);
  391.     endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
  392.     write_xms_store(info, (void FAR *) endbuffer,
  393.             file_offset + byte_count - 1L, 2L);
  394.   }
  395. }
  396.  
  397.  
  398. METHODDEF void
  399. close_xms_store (backing_store_ptr info)
  400. {
  401.   XMScontext ctx;
  402.  
  403.   ctx.dx = info->handle.xms_handle;
  404.   ctx.ax = 0x0a00;
  405.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  406.   TRACEMS1(methods, 1, "Freed XMS handle %u", info->handle.xms_handle);
  407.   /* we ignore any error return from the driver */
  408. }
  409.  
  410.  
  411. LOCAL boolean
  412. open_xms_store (backing_store_ptr info, long total_bytes_needed)
  413. {
  414.   XMScontext ctx;
  415.  
  416.   /* Get address of XMS driver */
  417.   jxms_getdriver((XMSDRIVER far *) & xms_driver);
  418.   if (xms_driver == NULL)
  419.     return FALSE;        /* no driver to be had */
  420.  
  421.   /* Get version number, must be >= 2.00 */
  422.   ctx.ax = 0x0000;
  423.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  424.   if (ctx.ax < (unsigned short) 0x0200)
  425.     return FALSE;
  426.  
  427.   /* Try to get space (expressed in kilobytes) */
  428.   ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
  429.   ctx.ax = 0x0900;
  430.   jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
  431.   if (ctx.ax != 1)
  432.     return FALSE;
  433.  
  434.   /* Succeeded, save the handle and away we go */
  435.   info->handle.xms_handle = ctx.dx;
  436.   info->read_backing_store = read_xms_store;
  437.   info->write_backing_store = write_xms_store;
  438.   info->close_backing_store = close_xms_store;
  439.   TRACEMS1(methods, 1, "Obtained XMS handle %u", ctx.dx);
  440.   return TRUE;            /* succeeded */
  441. }
  442.  
  443. #endif /* XMS_SUPPORTED */
  444.  
  445.  
  446. /*
  447.  * Access methods for expanded memory.
  448.  */
  449.  
  450. #if EMS_SUPPORTED
  451.  
  452. /* The EMS move specification structure requires word and long fields aligned
  453.  * at odd byte boundaries.  Some compilers will align struct fields at even
  454.  * byte boundaries.  While it's usually possible to force byte alignment,
  455.  * that causes an overall performance penalty and may pose problems in merging
  456.  * JPEG into a larger application.  Instead we accept some rather dirty code
  457.  * here.  Note this code would fail if the hardware did not allow odd-byte
  458.  * word & long accesses, but all 80x86 CPUs do.
  459.  */
  460.  
  461. typedef void far * EMSPTR;
  462.  
  463. typedef union {            /* EMS move specification structure */
  464.     long length;        /* It's easy to access first 4 bytes */
  465.     char bytes[18];        /* Misaligned fields in here! */
  466.       } EMSspec;
  467.  
  468. /* Macros for accessing misaligned fields */
  469. #define FIELD_AT(spec,offset,type)  (*((type *) &(spec.bytes[offset])))
  470. #define SRC_TYPE(spec)        FIELD_AT(spec,4,char)
  471. #define SRC_HANDLE(spec)    FIELD_AT(spec,5,EMSH)
  472. #define SRC_OFFSET(spec)    FIELD_AT(spec,7,unsigned short)
  473. #define SRC_PAGE(spec)        FIELD_AT(spec,9,unsigned short)
  474. #define SRC_PTR(spec)        FIELD_AT(spec,7,EMSPTR)
  475. #define DST_TYPE(spec)        FIELD_AT(spec,11,char)
  476. #define DST_HANDLE(spec)    FIELD_AT(spec,12,EMSH)
  477. #define DST_OFFSET(spec)    FIELD_AT(spec,14,unsigned short)
  478. #define DST_PAGE(spec)        FIELD_AT(spec,16,unsigned short)
  479. #define DST_PTR(spec)        FIELD_AT(spec,14,EMSPTR)
  480.  
  481. #define EMSPAGESIZE    16384L    /* gospel, see the EMS specs */
  482.  
  483. #define HIBYTE(W)  (((W) >> 8) & 0xFF)
  484. #define LOBYTE(W)  ((W) & 0xFF)
  485.  
  486.  
  487. METHODDEF void
  488. read_ems_store (backing_store_ptr info, void FAR * buffer_address,
  489.         long file_offset, long byte_count)
  490. {
  491.   EMScontext ctx;
  492.   EMSspec spec;
  493.  
  494.   spec.length = byte_count;
  495.   SRC_TYPE(spec) = 1;
  496.   SRC_HANDLE(spec) = info->handle.ems_handle;
  497.   SRC_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  498.   SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
  499.   DST_TYPE(spec) = 0;
  500.   DST_HANDLE(spec) = 0;
  501.   DST_PTR(spec)    = buffer_address;
  502.   
  503.   ctx.ds_si = (void far *) & spec;
  504.   ctx.ax = 0x5700;        /* move memory region */
  505.   jems_calldriver((EMScontext far *) & ctx);
  506.   if (HIBYTE(ctx.ax) != 0)
  507.     ERREXIT(methods, "read from expanded memory failed");
  508. }
  509.  
  510.  
  511. METHODDEF void
  512. write_ems_store (backing_store_ptr info, void FAR * buffer_address,
  513.          long file_offset, long byte_count)
  514. {
  515.   EMScontext ctx;
  516.   EMSspec spec;
  517.  
  518.   spec.length = byte_count;
  519.   SRC_TYPE(spec) = 0;
  520.   SRC_HANDLE(spec) = 0;
  521.   SRC_PTR(spec)    = buffer_address;
  522.   DST_TYPE(spec) = 1;
  523.   DST_HANDLE(spec) = info->handle.ems_handle;
  524.   DST_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
  525.   DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
  526.   
  527.   ctx.ds_si = (void far *) & spec;
  528.   ctx.ax = 0x5700;        /* move memory region */
  529.   jems_calldriver((EMScontext far *) & ctx);
  530.   if (HIBYTE(ctx.ax) != 0)
  531.     ERREXIT(methods, "write to expanded memory failed");
  532. }
  533.  
  534.  
  535. METHODDEF void
  536. close_ems_store (backing_store_ptr info)
  537. {
  538.   EMScontext ctx;
  539.  
  540.   ctx.ax = 0x4500;
  541.   ctx.dx = info->handle.ems_handle;
  542.   jems_calldriver((EMScontext far *) & ctx);
  543.   TRACEMS1(methods, 1, "Freed EMS handle %u", info->handle.ems_handle);
  544.   /* we ignore any error return from the driver */
  545. }
  546.  
  547.  
  548. LOCAL boolean
  549. open_ems_store (backing_store_ptr info, long total_bytes_needed)
  550. {
  551.   EMScontext ctx;
  552.  
  553.   /* Is EMS driver there? */
  554.   if (! jems_available())
  555.     return FALSE;
  556.  
  557.   /* Get status, make sure EMS is OK */
  558.   ctx.ax = 0x4000;
  559.   jems_calldriver((EMScontext far *) & ctx);
  560.   if (HIBYTE(ctx.ax) != 0)
  561.     return FALSE;
  562.  
  563.   /* Get version, must be >= 4.0 */
  564.   ctx.ax = 0x4600;
  565.   jems_calldriver((EMScontext far *) & ctx);
  566.   if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
  567.     return FALSE;
  568.  
  569.   /* Try to allocate requested space */
  570.   ctx.ax = 0x4300;
  571.   ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
  572.   jems_calldriver((EMScontext far *) & ctx);
  573.   if (HIBYTE(ctx.ax) != 0)
  574.     return FALSE;
  575.  
  576.   /* Succeeded, save the handle and away we go */
  577.   info->handle.ems_handle = ctx.dx;
  578.   info->read_backing_store = read_ems_store;
  579.   info->write_backing_store = write_ems_store;
  580.   info->close_backing_store = close_ems_store;
  581.   TRACEMS1(methods, 1, "Obtained EMS handle %u", ctx.dx);
  582.   return TRUE;            /* succeeded */
  583. }
  584.  
  585. #endif /* EMS_SUPPORTED */
  586.  
  587.  
  588. /*
  589.  * Initial opening of a backing-store object.
  590.  */
  591.  
  592. GLOBAL void
  593. jopen_backing_store (backing_store_ptr info, long total_bytes_needed)
  594. {
  595.   /* Try extended memory, then expanded memory, then regular file. */
  596. #if XMS_SUPPORTED
  597.   if (open_xms_store(info, total_bytes_needed))
  598.     return;
  599. #endif
  600. #if EMS_SUPPORTED
  601.   if (open_ems_store(info, total_bytes_needed))
  602.     return;
  603. #endif
  604.   if (open_file_store(info, total_bytes_needed))
  605.     return;
  606.   ERREXIT(methods, "Failed to create temporary file");
  607. }
  608.  
  609.  
  610. /*
  611.  * These routines take care of any system-dependent initialization and
  612.  * cleanup required.  Keep in mind that jmem_term may be called more than
  613.  * once.
  614.  */
  615.  
  616. GLOBAL void
  617. jmem_init (external_methods_ptr emethods)
  618. {
  619.   methods = emethods;        /* save struct addr for error exit access */
  620.   emethods->max_memory_to_use = DEFAULT_MAX_MEM;
  621.   total_used = 0;
  622.   next_file_num = 0;
  623. }
  624.  
  625. GLOBAL void
  626. jmem_term (void)
  627. {
  628.   /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
  629.    * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
  630.    */
  631. #ifdef NEED_FHEAPMIN
  632.   _fheapmin();
  633. #endif
  634. }
  635.