Exemple #1
0
void *_tc_recdecode(const void *ptr, int size, int *sp, void *op){
  char *res = MYMALLOC(size + 1);
  if(!res) return NULL;
  memcpy(res, ptr, size);
  *sp = size;
  return res;
}
Exemple #2
0
void *_tc_recdecode(const void *ptr, int size, int *sp, void *op){
  if(!_tc_lzo_init){
    if(lzo_init() != LZO_E_OK) return NULL;
    _tc_lzo_init = false;
  }
  lzo_bytep buf;
  lzo_uint bsiz;
  int rat = 6;
  while(true){
    bsiz = (size + 256) * rat + 3;
    buf = MYMALLOC(bsiz + 1);
    if(!buf) return NULL;
    int rv = lzo1x_decompress_safe((lzo_bytep)ptr, size, buf, &bsiz, NULL);
    if(rv == LZO_E_OK){
      break;
    } else if(rv == LZO_E_OUTPUT_OVERRUN){
      MYFREE(buf);
      rat *= 2;
    } else {
      MYFREE(buf);
      return NULL;
    }
  }
  buf[bsiz] = '\0';
  if(sp) *sp = bsiz;
  return (char *)buf;
}
Exemple #3
0
void DMUMPS_alloc(DMUMPS_STRUC_C **dmumps_par){

  MYMALLOC((*dmumps_par),1,DMUMPS_STRUC_C);
  (*dmumps_par)->irn  = NULL;
  (*dmumps_par)->jcn  = NULL;
  (*dmumps_par)->a  = NULL;
  (*dmumps_par)->irn_loc  = NULL;
  (*dmumps_par)->jcn_loc  = NULL;
  (*dmumps_par)->a_loc  = NULL;
  (*dmumps_par)->eltptr  = NULL;
  (*dmumps_par)->eltvar  = NULL;
  (*dmumps_par)->a_elt  = NULL;
  (*dmumps_par)->perm_in  = NULL;
  (*dmumps_par)->colsca  = NULL;
  (*dmumps_par)->rowsca  = NULL;
  (*dmumps_par)->rhs  = NULL;
  (*dmumps_par)->redrhs  = NULL;
  (*dmumps_par)->rhs_sparse = NULL;
  (*dmumps_par)->irhs_sparse = NULL;
  (*dmumps_par)->irhs_ptr = NULL;
  (*dmumps_par)->pivnul_list  = NULL;
  (*dmumps_par)->listvar_schur  = NULL;
  (*dmumps_par)->schur  = NULL;
  (*dmumps_par)->sym_perm  = NULL;
  (*dmumps_par)->uns_perm  = NULL;
}
Exemple #4
0
static VALUE
swinfont_new(int argc,VALUE * argv, VALUE klass){
/* argv:  fontname,height [,style,weight,width,escape,orient,pitchfamily] */
/*
pitch:  0 as default,1 as fixed, 2 as variable, 0x4 for truetype
family: 0x0 as dontcare,0x10 as roman, 0x20 as swiss,0x30 as modern,0x40 as script
        0x50 as decorative
weight: 0-9
*/

	struct SwinFont* sf;
	VALUE robj;

	int   height,width,escape,orient,weight;
	DWORD italic,underline,strike; /*,charset,oprec,cprec,quality; */ 
	DWORD pitchfamily;
	unsigned char charset;
	VALUE faceobj;
	TCHAR* face;
	int facelen;

	if(argc<2){
		rb_raise(rb_eArgError,"Need font face name and height");
		return Qfalse;
	}

    robj = Data_Make_Struct(cSwinFont, struct SwinFont, 0, release_font, sf);
	faceobj = SWIN_API_STR(argv[0]);
	facelen = RSTRING_LEN(faceobj);
/*	face = sf->fontname = malloc(facelen+1);*/
	MYMALLOC(sf->fontname,facelen+1,Qfalse);
	face = sf->fontname;
	lstrcpyn(face, (TCHAR*)RSTRING_PTR(faceobj),facelen/sizeof(TCHAR)+1);

    sf->height = height = NUM2INT(argv[1]);

	sf->style = (argc>2 && argv[2]!=Qnil)? NUM2UINT(argv[2]) : 0;
	italic = (sf->style) & SWINFONT_ITALIC;
	underline = (sf->style) & SWINFONT_ULINE;
	strike = (sf->style) & SWINFONT_STRIKE;

	sf->weight = weight = ((argc>3 && argv[3]!=Qnil)? NUM2INT(argv[3]) : 0)*100;
	sf->width  = width = (argc>4 && argv[4]!=Qnil)? NUM2INT(argv[4]) : 0;
	sf->escape = escape = (argc>5 && argv[5]!=Qnil)? NUM2INT(argv[5]) : 0;
	sf->orient = orient = (argc>6 && argv[6]!=Qnil)? NUM2INT(argv[6]) : 0;
	sf->pitchfamily = pitchfamily = (argc>7 && argv[7]!=Qnil)? NUM2INT(argv[7]) : 0x04;
	sf->charset = charset = (argc>8 && argv[8]!=Qnil)? NUM2INT(argv[8]) : DEFAULT_CHARSET;

	sf->hfont = CreateFont(height,width,escape,orient,weight,
	                  italic,underline,strike,charset,
	                  OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
	                  pitchfamily,face);
	if(!sf->hfont){
		rb_raise(rb_eRuntimeError,"failed to create font");
		return Qfalse;
	}
	return robj;
}
Exemple #5
0
/***************************************************************************
 *
 *                   block-cache related functions
 *
 ***************************************************************************
 */
int
bc_init(void) {
    if (unlikely(blk_cache_init))
        return 1;

    if (unlikely(!enable_blk_cache))
        return 0;

    if (!(blk_cache = (block_cache_t*)MYMALLOC(sizeof(block_cache_t))))
        return 0;

    blk_cache->blks = rbt_create();
    if (!blk_cache->blks) {
        free(blk_cache);
        return 0;
    }

    lru_init();
    blk_cache_init = 1;

    return 1;
}
Exemple #6
0
void mexFunction(int nlhs, mxArray *plhs[ ],
                 int nrhs, const mxArray *prhs[ ]) { 
  
  int i,j,pos;
  int *ptr_int;
  double *ptr_matlab;
#if MUMPS_ARITH == MUMPS_ARITH_z
  double *ptri_matlab;
#endif
  mwSize tmp_m,tmp_n;

  /* C pointer for input parameters */
  size_t inst_address;
  mwSize n,m,ne, netrue ;
  int job;
  mwIndex *irn_in,*jcn_in;
  
  /* variable for multiple and sparse rhs */
  int posrhs;
          mwSize  nbrhs,ldrhs, nz_rhs;
  mwIndex *irhs_ptr, *irhs_sparse;
  double *rhs_sparse;
#if MUMPS_ARITH == MUMPS_ARITH_z
  double *im_rhs_sparse;
#endif

  DMUMPS_STRUC_C *dmumps_par;
  int dosolve = 0;
  int donullspace = 0;
  int doanalysis = 0;
  int dofactorize = 0;
  
  
  EXTRACT_FROM_MATLAB_TOVAL(JOB,job);

  doanalysis = (job == 1 || job == 4 || job == 6);
  dofactorize = (job == 2 || job == 4 || job == 5 || job == 6);
  dosolve = (job == 3 || job == 5 || job == 6);

  if(job == -1){
    DMUMPS_alloc(&dmumps_par);
    EXTRACT_FROM_MATLAB_TOVAL(SYM,dmumps_par->sym);
    dmumps_par->job = -1;
    dmumps_par->par = 1;
    dmumps_c(dmumps_par);
    dmumps_par->nz = -1;
    dmumps_par->nz_alloc = -1;
  }else{
    EXTRACT_FROM_MATLAB_TOVAL(INST,inst_address);
    ptr_int = (int *) inst_address;

    dmumps_par = (DMUMPS_STRUC_C *) ptr_int;

    if(job == -2){
      dmumps_par->job = -2;
      dmumps_c(dmumps_par);
      /* If colsca/rowsca were freed by MUMPS,
         dmumps_par->colsca/rowsca are now null.
         Application of MYFREE in call below thus ok */
      DMUMPS_free(&dmumps_par);
    }else{

      /* check of input arguments */
      n = mxGetN(A_IN);
      m = mxGetM(A_IN);

      if (!mxIsSparse(A_IN) || n != m )
          mexErrMsgTxt("Input matrix must be a sparse square matrix");
      
      jcn_in = mxGetJc(A_IN);
      ne = jcn_in[n];
      irn_in = mxGetIr(A_IN);
      dmumps_par->n = (int)n;
      if(dmumps_par->n != n)
          mexErrMsgTxt("Input is too big; will not work...barfing out\n");
      
      if(dmumps_par->sym != 0)
          netrue = (n+ne)/2;
      else
          netrue = ne;
      
      if(dmumps_par->nz_alloc < netrue || dmumps_par->nz_alloc >= 2*netrue){  
        MYFREE(dmumps_par->jcn);
        MYFREE(dmumps_par->irn);
        MYFREE(dmumps_par->a);
        MYMALLOC((dmumps_par->jcn),(int)netrue,int);
        MYMALLOC((dmumps_par->irn),(int)netrue,int);
        MYMALLOC((dmumps_par->a),(int)netrue,double2);
        dmumps_par->nz_alloc = (int)netrue;
    if (dmumps_par->nz_alloc != netrue)
        mexErrMsgTxt("Input is too big; will not work...barfing out\n");
      }


      if(dmumps_par->sym == 0){
        /* if analysis already performed then we only need to read
           numerical values
           Note that we suppose that matlab did not change the internal
           format of the matrix between the 2 calls */
        if(doanalysis){ 
          /* || dmumps_par->info[22] == 0 */
          for(i=0;i<dmumps_par->n;i++){
            for(j=jcn_in[i];j<jcn_in[i+1];j++){
              (dmumps_par->jcn)[j] = i+1;
              (dmumps_par->irn)[j] = ((int)irn_in[j])+1;
            }
          }
        }
    dmumps_par->nz = (int)ne;
    if( dmumps_par->nz != ne)
        mexErrMsgTxt("Input is too big; will not work...barfing out\n");
#if MUMPS_ARITH == MUMPS_ARITH_z
        ptr_matlab = mxGetPr(A_IN);
        for(i=0;i<dmumps_par->nz;i++){                                                   
          ((dmumps_par->a)[i]).r = ptr_matlab[i];
        }
        ptr_matlab = mxGetPi(A_IN);
        if(ptr_matlab){
          for(i=0;i<dmumps_par->nz;i++){                                                   
            ((dmumps_par->a)[i]).i = ptr_matlab[i];
          }
        }else{
          for(i=0;i<dmumps_par->nz;i++){                                                   
             ((dmumps_par->a)[i]).i = 0.0;
             }
        }
#else
        ptr_matlab = mxGetPr(A_IN);
        for(i=0;i<dmumps_par->nz;i++){                                                   
          (dmumps_par->a)[i] = ptr_matlab[i];
        }
#endif
      }else{
        /* in the symmetric case we do not need to check doanalysis */
        pos = 0;
        ptr_matlab = mxGetPr(A_IN);
#if MUMPS_ARITH == MUMPS_ARITH_z
        ptri_matlab = mxGetPi(A_IN);
#endif
        for(i=0;i<dmumps_par->n;i++){
          for(j=jcn_in[i];j<jcn_in[i+1];j++){
            if(irn_in[j] >= i){
              if(pos >= netrue)
              mexErrMsgTxt("Input matrix must be symmetric");
              (dmumps_par->jcn)[pos] = i+1;
              (dmumps_par->irn)[pos] = (int)irn_in[j]+1;
#if MUMPS_ARITH == MUMPS_ARITH_z
              ((dmumps_par->a)[pos]).r = ptr_matlab[j];
              if(ptri_matlab){
                ((dmumps_par->a)[pos]).i = ptri_matlab[j];
              }else{
                ((dmumps_par->a)[pos]).i = 0.0;
              }
#else
              (dmumps_par->a)[pos] = ptr_matlab[j];
#endif
              pos++;
             }
          }
        }
        dmumps_par->nz = pos;
      }
    

      EXTRACT_FROM_MATLAB_TOVAL(JOB,dmumps_par->job);
      EXTRACT_FROM_MATLAB_TOARR(ICNTL_IN,dmumps_par->icntl,int,40);
      EXTRACT_FROM_MATLAB_TOARR(CNTL_IN,dmumps_par->cntl,double,15);
      EXTRACT_FROM_MATLAB_TOPTR(PERM_IN,(dmumps_par->perm_in),int,((int)n));

      /* colsca and rowsca are treated differently: it may happen that
         dmumps_par-> colsca is nonzero because it was set to a nonzero
         value on output (COLSCA_OUT) from MUMPS. Unfortunately if scaling
         was on output, one cannot currently provide scaling on input
         afterwards without reinitializing the instance */

      EXTRACT_SCALING_FROM_MATLAB_TOPTR(COLSCA_IN,(dmumps_par->colsca),(dmumps_par->colsca_from_mumps),((int)n)); /* type always double */
      EXTRACT_SCALING_FROM_MATLAB_TOPTR(ROWSCA_IN,(dmumps_par->rowsca),(dmumps_par->rowsca_from_mumps),((int)n)); /* type always double */

      EXTRACT_FROM_MATLAB_TOARR(KEEP_IN,dmumps_par->keep,int,500);
      EXTRACT_FROM_MATLAB_TOARR(DKEEP_IN,dmumps_par->dkeep,double,230);

      dmumps_par->size_schur = (int)mxGetN(VAR_SCHUR);
      EXTRACT_FROM_MATLAB_TOPTR(VAR_SCHUR,(dmumps_par->listvar_schur),int,dmumps_par->size_schur);
      if(!dmumps_par->listvar_schur) dmumps_par->size_schur = 0;

      ptr_matlab = mxGetPr (RHS_IN);

/*
 * To follow the "spirit" of the Matlab/Scilab interfaces, treat case of null
 * space separately. In that case, we initialize lrhs and nrhs, automatically
 * allocate the space needed, and do not rely on what is provided by the user
 * in component RHS, that is not touched.
 *
 * Note that, at the moment, the user should not call the solution step combined
 * with the factorization step when he/she sets icntl[25-1] to a non-zero value.
 * Hence we suppose in the following that infog[28-1] is available and that we
 * can use it.
 * 
 * For users of scilab/matlab, it would still be nice to be able to set ICNTL(25)=-1,
 * and use JOB=6. If we want to make such a feature available, we should
 * call separately job=2 and job=3 even if job=5 or 6 and set nbrhs (and allocate
 * space correctly) between job=2 and job=3 calls to MUMPS.
 *
 */
      if ( dmumps_par->icntl[25-1] == -1 && dmumps_par->infog[28-1] > 0 ) {
          dmumps_par->nrhs=dmumps_par->infog[28-1];
          donullspace = dosolve;
         }
      else if ( dmumps_par->icntl[25-1] > 0 && dmumps_par->icntl[25-1] <= dmumps_par->infog[28-1] ) {
           dmumps_par->nrhs=1;
           donullspace = dosolve;
         }
      else {
           donullspace=0;
         }
      if (donullspace) {
        nbrhs=dmumps_par->nrhs; ldrhs=n;
        dmumps_par->lrhs=(int)n;
        MYMALLOC((dmumps_par->rhs),((dmumps_par->n)*(dmumps_par->nrhs)),double2);
         }
      else if((!dosolve) || ptr_matlab[0] == -9999 ) { /* rhs not already provided, or not used */
/*     Case where dosolve is true and ptr_matlab[0]=-9999, this could cause problems:
 *        1/ RHS was not initialized while it should have been
 *        2/ RHS was explicitely initialized to -9999 but is not allocated of the right size
 */
        EXTRACT_CMPLX_FROM_MATLAB_TOPTR(RHS_IN,(dmumps_par->rhs),double,1);
      }else{
Exemple #7
0
/**************************************************************************
 *
 *       Debugging Support & Misc "cold" functions
 *
 **************************************************************************
 */
const lm_status_t*
lm_get_status(void) {
    if (!alloc_info)
        return NULL;

    lm_status_t* s = (lm_status_t *)MYMALLOC(sizeof(lm_status_t));
    s->first_page = alloc_info->first_page;
    s->page_num = alloc_info->page_num;
    s->idx_to_id = alloc_info->idx_2_id_adj;
    s->alloc_blk_num = 0;
    s->free_blk_num = 0;
    s->free_blk_info = NULL;
    s->alloc_blk_info = NULL;
    rb_tree_t* rbt = &alloc_info->alloc_blks;
    int alloc_blk_num = rbt_size(rbt);

    /* Populate allocated block info */
    if (alloc_blk_num) {
        block_info_t* ai;
        ai = (block_info_t*)MYMALLOC(sizeof(block_info_t) * alloc_blk_num);

        rb_iter_t iter, iter_e;
        int idx = 0;
        for (iter = rbt_iter_begin(rbt), iter_e = rbt_iter_end(rbt);
             iter != iter_e;
             iter = rbt_iter_inc(rbt, iter)) {
            rb_node_t* blk = rbt_iter_deref(iter);
            ai[idx].page_idx = blk->key;
            ai[idx].size = blk->value;
            ai[idx].order = alloc_info->page_info[blk->key].order;
            idx++;
        }

        s->alloc_blk_info = ai;
        s->alloc_blk_num = idx;
    }

    /* Populate free block info */
    int free_blk_num = 0;
    int i, e;
    for (i = 0, e = alloc_info->max_order; i <= e; i++) {
        free_blk_num += rbt_size(alloc_info->free_blks + i);
    }
    if (free_blk_num) {
        block_info_t* fi;
        fi = (block_info_t*)MYMALLOC(sizeof(block_info_t) * free_blk_num);

        int idx = 0;
        int page_size_log2 = alloc_info->page_size_log2;
        for (i = 0, e = alloc_info->max_order; i <= e; i++) {
            rb_tree_t* rbt = alloc_info->free_blks + i;

            rb_iter_t iter, iter_e;
            for (iter = rbt_iter_begin(rbt), iter_e = rbt_iter_end(rbt);
                 iter != iter_e;
                 iter = rbt_iter_inc(rbt, iter)) {
                rb_node_t* nd = rbt_iter_deref(iter);
                fi[idx].page_idx = nd->key;
                fi[idx].order = alloc_info->page_info[nd->key].order;
                fi[idx].size = (1 << fi[idx].order) << page_size_log2;
                idx++;
            }
        }
        ASSERT(idx == free_blk_num);

        s->free_blk_info = fi;
        s->free_blk_num = idx;
    }

    return s;
}
Exemple #8
0
/* Initialize the page allocator, return 1 on success, 0 otherwise. */
int
lm_init_page_alloc(lm_chunk_t* chunk, ljmm_opt_t* mm_opt) {
    if (!chunk) {
        /* Trunk is not yet allocated */
        return 0;
    }

    if (alloc_info) {
        /* This function was succesfully invoked before */
        return 1;
    }

    int page_num = chunk->page_num;
    if (unlikely(mm_opt != NULL)) {
        int pn = mm_opt->dbg_alloc_page_num;
        if (((pn > 0) && (pn > page_num)) || !pn)
            return 0;
        else if (pn > 0) {
            page_num = pn;
        }

        if (!bc_set_parameter(mm_opt->enable_block_cache,
                              mm_opt->blk_cache_in_page)) {
            return 0;
        }
    }

    int alloc_sz = sizeof(lm_alloc_t) +
                   sizeof(lm_page_t) * (page_num + 1);

    alloc_info = (lm_alloc_t*) MYMALLOC(alloc_sz);
    if (!alloc_info) {
        errno = ENOMEM;
        return 0;
    }

    alloc_info->first_page = chunk->base;
    alloc_info->page_num   = page_num;
    alloc_info->page_size  = chunk->page_size;
    alloc_info->page_size_log2 = log2_int32(chunk->page_size);

    /* Init the page-info */
    char* p =  (char*)(alloc_info + 1);
    int align = __alignof__(lm_page_t);
    p = (char*)((((intptr_t)p) + align - 1) & ~align);
    alloc_info->page_info = (lm_page_t*)p;

    int i;
    lm_page_t* pi = alloc_info->page_info;
    for (i = 0; i < page_num; i++) {
        pi[i].order = INVALID_ORDER;
        pi[i].flags = 0;
    }

    /* Init the buddy allocator */
    int e;
    rb_tree_t* free_blks = &alloc_info->free_blks[0];
    for (i = 0, e = MAX_ORDER; i < e; i++)
        rbt_init(&free_blks[i]);
    rbt_init(&alloc_info->alloc_blks);

    /* Determine the max order */
    int max_order = 0;
    unsigned int bitmask;
    for (bitmask = 0x80000000/*2G*/, max_order = 31;
         bitmask;
         bitmask >>= 1, max_order --) {
        if (bitmask & page_num)
            break;
    }
    alloc_info->max_order = max_order;

    /* So, the ID of biggest block's first page is "1 << order". e.g.
     * Suppose the chunk contains 11 pages, which will be divided into 3
     * blocks, eaching containing 1, 2 and 8 pages. The indices of these
     * blocks are 0, 1, 3 respectively, and their IDs are 5, 6, and 8
     * respectively. In this case:
     *    alloc_info->idx_2_id_adj == 5 == page_id(*) - page_idx(*)
     */
    int idx_2_id_adj = (1 << max_order) - (page_num & ((1 << max_order) - 1));
    alloc_info->idx_2_id_adj = idx_2_id_adj;

    /* Divide the chunk into blocks, smaller block first. Smaller blocks
     * are likely allocated and deallocated frequently. Therefore, they are
     * better off residing closer to data segment.
     */
    int page_idx = 0;
    int order = 0;
    for (bitmask = 1, order = 0;
         bitmask != 0;
         bitmask = bitmask << 1, order++) {
        if (page_num & bitmask) {
            add_free_block(page_idx, order);
            page_idx += (1 << order);
        }
    }

    /*init the block cache */
    bc_init();

    return 1;
}
Exemple #9
0
static char *_tc_deflate_impl(const char *ptr, int size, int *sp, int mode){
  assert(ptr && size >= 0 && sp);
  z_stream zs;
  zs.zalloc = Z_NULL;
  zs.zfree = Z_NULL;
  zs.opaque = Z_NULL;
  switch(mode){
    case _TCZMRAW:
      if(deflateInit2(&zs, 5, Z_DEFLATED, -15, 7, Z_DEFAULT_STRATEGY) != Z_OK)
        return NULL;
      break;
    case _TCZMGZIP:
      if(deflateInit2(&zs, 6, Z_DEFLATED, 15 + 16, 9, Z_DEFAULT_STRATEGY) != Z_OK)
        return NULL;
      break;
    default:
      if(deflateInit2(&zs, 6, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
        return NULL;
      break;
  }
  int asiz = size + 16;
  if(asiz < ZLIBBUFSIZ) asiz = ZLIBBUFSIZ;
  char *buf;
  if(!(buf = MYMALLOC(asiz))){
    deflateEnd(&zs);
    return NULL;
  }
  unsigned char obuf[ZLIBBUFSIZ];
  int bsiz = 0;
  zs.next_in = (unsigned char *)ptr;
  zs.avail_in = size;
  zs.next_out = obuf;
  zs.avail_out = ZLIBBUFSIZ;
  int rv;
  while((rv = deflate(&zs, Z_FINISH)) == Z_OK){
    int osiz = ZLIBBUFSIZ - zs.avail_out;
    if(bsiz + osiz > asiz){
      asiz = asiz * 2 + osiz;
      char *swap;
      if(!(swap = MYREALLOC(buf, asiz))){
        MYFREE(buf);
        deflateEnd(&zs);
        return NULL;
      }
      buf = swap;
    }
    memcpy(buf + bsiz, obuf, osiz);
    bsiz += osiz;
    zs.next_out = obuf;
    zs.avail_out = ZLIBBUFSIZ;
  }
  if(rv != Z_STREAM_END){
    MYFREE(buf);
    deflateEnd(&zs);
    return NULL;
  }
  int osiz = ZLIBBUFSIZ - zs.avail_out;
  if(bsiz + osiz + 1 > asiz){
    asiz = asiz * 2 + osiz;
    char *swap;
    if(!(swap = MYREALLOC(buf, asiz))){
      MYFREE(buf);
      deflateEnd(&zs);
      return NULL;
    }
    buf = swap;
  }
  memcpy(buf + bsiz, obuf, osiz);
  bsiz += osiz;
  buf[bsiz] = '\0';
  if(mode == _TCZMRAW) bsiz++;
  *sp = bsiz;
  deflateEnd(&zs);
  return buf;
}
Exemple #10
0
static char *_tc_bzdecompress_impl(const char *ptr, int size, int *sp){
  assert(ptr && size >= 0 && sp);
  bz_stream zs;
  zs.bzalloc = NULL;
  zs.bzfree = NULL;
  zs.opaque = NULL;
  if(BZ2_bzDecompressInit(&zs, 0, 0) != BZ_OK) return NULL;
  int asiz = size * 2 + 16;
  if(asiz < BZIPBUFSIZ) asiz = BZIPBUFSIZ;
  char *buf;
  if(!(buf = MYMALLOC(asiz))){
    BZ2_bzDecompressEnd(&zs);
    return NULL;
  }
  char obuf[BZIPBUFSIZ];
  int bsiz = 0;
  zs.next_in = (char *)ptr;
  zs.avail_in = size;
  zs.next_out = obuf;
  zs.avail_out = BZIPBUFSIZ;
  int rv;
  while((rv = BZ2_bzDecompress(&zs)) == BZ_OK){
    int osiz = BZIPBUFSIZ - zs.avail_out;
    if(bsiz + osiz >= asiz){
      asiz = asiz * 2 + osiz;
      char *swap;
      if(!(swap = MYREALLOC(buf, asiz))){
        MYFREE(buf);
        BZ2_bzDecompressEnd(&zs);
        return NULL;
      }
      buf = swap;
    }
    memcpy(buf + bsiz, obuf, osiz);
    bsiz += osiz;
    zs.next_out = obuf;
    zs.avail_out = BZIPBUFSIZ;
  }
  if(rv != BZ_STREAM_END){
    MYFREE(buf);
    BZ2_bzDecompressEnd(&zs);
    return NULL;
  }
  int osiz = BZIPBUFSIZ - zs.avail_out;
  if(bsiz + osiz >= asiz){
    asiz = asiz * 2 + osiz;
    char *swap;
    if(!(swap = MYREALLOC(buf, asiz))){
      MYFREE(buf);
      BZ2_bzDecompressEnd(&zs);
      return NULL;
    }
    buf = swap;
  }
  memcpy(buf + bsiz, obuf, osiz);
  bsiz += osiz;
  buf[bsiz] = '\0';
  *sp = bsiz;
  BZ2_bzDecompressEnd(&zs);
  return buf;
}