void Bresenham_Ellipse(int xc , int yc , int a, int b) { int sqa = a * a; int sqb = b * b; int P_x = ROUND_INT( (double)sqa/sqrt((double)(sqa+sqb)) ); int P_y = ROUND_INT( (double)sqb/sqrt((double)(sqa+sqb)) ); /* 生成第一象限内的上半部分椭圆弧 */ int x = 0; int y = b; int d = 4 * (sqb - b * sqa) + sqa; EllipsePlot(xc, yc, x, y); while(x <= P_x) { if(d <= 0) { d += 4 * sqb * (2 * x + 3); } else { d += 4 * sqb * (2 * x + 3) - 8 * sqa * (y - 1); y--; } x++; EllipsePlot(xc, yc, x, y); } /* 生成第一象限内的下半部分椭圆弧 */ x = a; y = 0; d = 4 * (sqa - a * sqb) + sqb; EllipsePlot(xc, yc, x, y); while(y < P_y) { if(d <= 0) { d += 4 * sqa * (2 * y + 3); } else { d += 4 * sqa * (2 * y + 3) - 8 * sqb * (x - 1); x--; } y++; EllipsePlot(xc, yc, x, y); } }
void EdgeScanMarkColor(EDGE3& e) { for(int y = e.ymax; y >= e.ymin; y--) { int x = ROUND_INT(e.xi); ComplementScanLineColor(x, MAX_X_CORD, y); e.xi -= e.dx; } }
void FenceScanMarkColor(EDGE3 e, int fence) { for(int y = e.ymax; y >= e.ymin; y--) { int x = ROUND_INT(e.xi); if(x > fence) { ComplementScanLineColor(fence, x, y); } else { ComplementScanLineColor(x, fence - 1, y); } e.xi -= e.dx; } }
/*Bresenham算法*/ void Bresenham_Ellipse(int xc , int yc , int a, int b) { int sqa = a * a; int sqb = b * b; int x = 0; int y = b; int d = 2 * sqb - 2 * b * sqa + sqa; EllipsePlot(xc, yc, x, y); int P_x = ROUND_INT( (double)sqa/sqrt((double)(sqa+sqb)) ); while(x <= P_x) { if(d < 0) { d += 2 * sqb * (2 * x + 3); } else { d += 2 * sqb * (2 * x + 3) - 4 * sqa * (y - 1); y--; } x++; EllipsePlot(xc, yc, x, y); } d = sqb * (x * x + x) + sqa * (y * y - y) - sqa * sqb; while(y >= 0) { EllipsePlot(xc, yc, x, y); y--; if(d < 0) { x++; d = d - 2 * sqa * y - sqa + 2 * sqb * x + 2 * sqb; } else { d = d - 2 * sqa * y - sqa; } } }
/* ============== R_CalcBones The list of bones[] should only be built and modified from within here ============== */ void R_CalcBones(mdsHeader_t *header, const refEntity_t *refent, int *boneList, int numBones) { int i; int *boneRefs; float torsoWeight; // if the entity has changed since the last time the bones were built, reset them if (memcmp(&lastBoneEntity, refent, sizeof(refEntity_t))) { // different, cached bones are not valid memset(validBones, 0, header->numBones); lastBoneEntity = *refent; // (SA) also reset these counter statics //----(SA) print stats for the complete model (not per-surface) if (r_bonesDebug->integer == 4 && totalrt) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, totalrv, totalv, totalrt, totalt, ( float )(100.0 * totalrt) / (float) totalt); } totalrv = totalrt = totalv = totalt = 0; } memset(newBones, 0, header->numBones); if (refent->oldframe == refent->frame) { backlerp = 0; frontlerp = 1; } else { backlerp = refent->backlerp; frontlerp = 1.0f - backlerp; } if (refent->oldTorsoFrame == refent->torsoFrame) { torsoBacklerp = 0; torsoFrontlerp = 1; } else { torsoBacklerp = refent->torsoBacklerp; torsoFrontlerp = 1.0f - torsoBacklerp; } frameSize = (int) (sizeof(mdsFrame_t) + (header->numBones - 1) * sizeof(mdsBoneFrameCompressed_t)); frame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->frame * frameSize); torsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->torsoFrame * frameSize); oldFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldframe * frameSize); oldTorsoFrame = ( mdsFrame_t * )((byte *)header + header->ofsFrames + refent->oldTorsoFrame * frameSize); // lerp all the needed bones (torsoParent is always the first bone in the list) cBoneList = frame->bones; cBoneListTorso = torsoFrame->bones; boneInfo = ( mdsBoneInfo_t * )((byte *)header + header->ofsBones); boneRefs = boneList; // Matrix3Transpose(refent->torsoAxis, torsoAxis); #ifdef HIGH_PRECISION_BONES if (qtrue) { #else if (!backlerp && !torsoBacklerp) { #endif for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBone(header, refent, boneInfo[*boneRefs].parent); } R_CalcBone(header, refent, *boneRefs); } } else // interpolated { cOldBoneList = oldFrame->bones; cOldBoneListTorso = oldTorsoFrame->bones; for (i = 0; i < numBones; i++, boneRefs++) { if (validBones[*boneRefs]) { // this bone is still in the cache bones[*boneRefs] = rawBones[*boneRefs]; continue; } // find our parent, and make sure it has been calculated if ((boneInfo[*boneRefs].parent >= 0) && (!validBones[boneInfo[*boneRefs].parent] && !newBones[boneInfo[*boneRefs].parent])) { R_CalcBoneLerp(header, refent, boneInfo[*boneRefs].parent); } R_CalcBoneLerp(header, refent, *boneRefs); } } // adjust for torso rotations torsoWeight = 0; boneRefs = boneList; for (i = 0; i < numBones; i++, boneRefs++) { thisBoneInfo = &boneInfo[*boneRefs]; bonePtr = &bones[*boneRefs]; // add torso rotation if (thisBoneInfo->torsoWeight > 0) { if (!newBones[*boneRefs]) { // just copy it back from the previous calc bones[*boneRefs] = oldBones[*boneRefs]; continue; } if (!(thisBoneInfo->flags & BONEFLAG_TAG)) { // 1st multiply with the bone->matrix // 2nd translation for rotation relative to bone around torso parent offset VectorSubtract(bonePtr->translation, torsoParentOffset, t); Matrix4FromAxisPlusTranslation(bonePtr->matrix, t, m1); // 3rd scaled rotation // 4th translate back to torso parent offset // use previously created matrix if available for the same weight if (torsoWeight != thisBoneInfo->torsoWeight) { Matrix4FromScaledAxisPlusTranslation(torsoAxis, thisBoneInfo->torsoWeight, torsoParentOffset, m2); torsoWeight = thisBoneInfo->torsoWeight; } // multiply matrices to create one matrix to do all calculations Matrix4MultiplyInto3x3AndTranslation(m2, m1, bonePtr->matrix, bonePtr->translation); } else // tag's require special handling { // rotate each of the axis by the torsoAngles LocalScaledMatrixTransformVector(bonePtr->matrix[0], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[0]); LocalScaledMatrixTransformVector(bonePtr->matrix[1], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[1]); LocalScaledMatrixTransformVector(bonePtr->matrix[2], thisBoneInfo->torsoWeight, torsoAxis, tmpAxis[2]); memcpy(bonePtr->matrix, tmpAxis, sizeof(tmpAxis)); // rotate the translation around the torsoParent VectorSubtract(bonePtr->translation, torsoParentOffset, t); LocalScaledMatrixTransformVector(t, thisBoneInfo->torsoWeight, torsoAxis, bonePtr->translation); VectorAdd(bonePtr->translation, torsoParentOffset, bonePtr->translation); } } } // backup the final bones memcpy(oldBones, bones, sizeof(bones[0]) * header->numBones); } #ifdef DBG_PROFILE_BONES #define DBG_SHOWTIME Ren_Print("%i: %i, ", di++, (dt = ri.Milliseconds()) - ldt); ldt = dt; #else #define DBG_SHOWTIME ; #endif /* ============== RB_SurfaceAnim ============== */ void RB_SurfaceAnim(mdsSurface_t *surface) { int j, k; refEntity_t *refent; int *boneList; mdsHeader_t *header; #ifdef DBG_PROFILE_BONES int di = 0, dt, ldt; dt = ri.Milliseconds(); ldt = dt; #endif refent = &backEnd.currentEntity->e; boneList = ( int * )((byte *)surface + surface->ofsBoneReferences); header = ( mdsHeader_t * )((byte *)surface + surface->ofsHeader); R_CalcBones(header, (const refEntity_t *)refent, boneList, surface->numBoneReferences); DBG_SHOWTIME // calculate LOD // TODO: lerp the radius and origin VectorAdd(refent->origin, frame->localOrigin, vec); lodRadius = frame->radius; lodScale = RB_CalcMDSLod(refent, vec, lodRadius, header->lodBias, header->lodScale); //DBG_SHOWTIME // modification to allow dead skeletal bodies to go below minlod (experiment) if (refent->reFlags & REFLAG_DEAD_LOD) { if (lodScale < 0.35) // allow dead to lod down to 35% (even if below surf->minLod) (%35 is arbitrary and probably not good generally. worked for the blackguard/infantry as a test though) { lodScale = 0.35; } render_count = ROUND_INT(surface->numVerts * lodScale); } else { render_count = ROUND_INT(surface->numVerts * lodScale); if (render_count < surface->minLod) { if (!(refent->reFlags & REFLAG_DEAD_LOD)) { render_count = surface->minLod; } } } if (render_count > surface->numVerts) { render_count = surface->numVerts; } RB_CheckOverflow(render_count, surface->numTriangles); //DBG_SHOWTIME // setup triangle list RB_CheckOverflow(surface->numVerts, surface->numTriangles * 3); //DBG_SHOWTIME collapse_map = ( int * )(( byte * )surface + surface->ofsCollapseMap); triangles = ( int * )((byte *)surface + surface->ofsTriangles); indexes = surface->numTriangles * 3; baseIndex = tess.numIndexes; baseVertex = tess.numVertexes; oldIndexes = baseIndex; tess.numVertexes += render_count; pIndexes = &tess.indexes[baseIndex]; //DBG_SHOWTIME if (render_count == surface->numVerts) { memcpy(pIndexes, triangles, sizeof(triangles[0]) * indexes); if (baseVertex) { glIndex_t *indexesEnd; for (indexesEnd = pIndexes + indexes ; pIndexes < indexesEnd ; pIndexes++) { *pIndexes += baseVertex; } } tess.numIndexes += indexes; } else { int *collapseEnd; pCollapse = collapse; for (j = 0; j < render_count; pCollapse++, j++) { *pCollapse = j; } pCollapseMap = &collapse_map[render_count]; for (collapseEnd = collapse + surface->numVerts ; pCollapse < collapseEnd; pCollapse++, pCollapseMap++) { *pCollapse = collapse[*pCollapseMap]; } for (j = 0 ; j < indexes ; j += 3) { p0 = collapse[*(triangles++)]; p1 = collapse[*(triangles++)]; p2 = collapse[*(triangles++)]; // FIXME // note: serious optimization opportunity here, // by sorting the triangles the following "continue" // could have been made into a "break" statement. if (p0 == p1 || p1 == p2 || p2 == p0) { continue; } *(pIndexes++) = baseVertex + p0; *(pIndexes++) = baseVertex + p1; *(pIndexes++) = baseVertex + p2; tess.numIndexes += 3; } baseIndex = tess.numIndexes; } //DBG_SHOWTIME // deform the vertexes by the lerped bones numVerts = surface->numVerts; v = ( mdsVertex_t * )((byte *)surface + surface->ofsVerts); tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); for (j = 0; j < render_count; j++, tempVert += 4, tempNormal += 4) { mdsWeight_t *w; VectorClear(tempVert); w = v->weights; for (k = 0 ; k < v->numWeights ; k++, w++) { bone = &bones[w->boneIndex]; LocalAddScaledMatrixTransformVectorTranslate(w->offset, w->boneWeight, bone->matrix, bone->translation, tempVert); } LocalMatrixTransformVector(v->normal, bones[v->weights[0].boneIndex].matrix, tempNormal); tess.texCoords0[baseVertex + j].v[0] = v->texCoords[0]; tess.texCoords0[baseVertex + j].v[1] = v->texCoords[1]; v = (mdsVertex_t *)&v->weights[v->numWeights]; } DBG_SHOWTIME if (r_bonesDebug->integer) { if (r_bonesDebug->integer < 3) { int i; // DEBUG: show the bones as a stick figure with axis at each bone boneRefs = ( int * )((byte *)surface + surface->ofsBoneReferences); for (i = 0; i < surface->numBoneReferences; i++, boneRefs++) { bonePtr = &bones[*boneRefs]; GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); for (j = 0; j < 3; j++) { VectorClear(vec); vec[j] = 1; qglColor3fv(vec); qglVertex3fv(bonePtr->translation); VectorMA(bonePtr->translation, 5, bonePtr->matrix[j], vec); qglVertex3fv(vec); } qglEnd(); // connect to our parent if it's valid if (validBones[boneInfo[*boneRefs].parent]) { qglLineWidth(2); qglBegin(GL_LINES); qglColor3f(.6, .6, .6); qglVertex3fv(bonePtr->translation); qglVertex3fv(bones[boneInfo[*boneRefs].parent].translation); qglEnd(); } qglLineWidth(1); } } if (r_bonesDebug->integer == 3 || r_bonesDebug->integer == 4) { int render_indexes = (tess.numIndexes - oldIndexes); // show mesh edges tempVert = ( float * )(tess.xyz + baseVertex); tempNormal = ( float * )(tess.normal + baseVertex); GL_Bind(tr.whiteImage); qglLineWidth(1); qglBegin(GL_LINES); qglColor3f(.0, .0, .8); pIndexes = &tess.indexes[oldIndexes]; for (j = 0; j < render_indexes / 3; j++, pIndexes += 3) { qglVertex3fv(tempVert + 4 * pIndexes[0]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[1]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[2]); qglVertex3fv(tempVert + 4 * pIndexes[0]); } qglEnd(); // track debug stats if (r_bonesDebug->integer == 4) { totalrv += render_count; totalrt += render_indexes / 3; totalv += surface->numVerts; totalt += surface->numTriangles; } if (r_bonesDebug->integer == 3) { Ren_Print("Lod %.2f verts %4d/%4d tris %4d/%4d (%.2f%%)\n", lodScale, render_count, surface->numVerts, render_indexes / 3, surface->numTriangles, ( float )(100.0 * render_indexes / 3) / (float) surface->numTriangles); } } } if (r_bonesDebug->integer > 1) { // dont draw the actual surface tess.numIndexes = oldIndexes; tess.numVertexes = baseVertex; return; } #ifdef DBG_PROFILE_BONES Ren_Print("\n"); #endif }
/* ================= R_ComputeLOD ================= */ static int R_ComputeLOD(trRefEntity_t *ent) { int lod; if (tr.currentModel->numLods < 2) { // model has only 1 LOD level, skip computations and bias lod = 0; } else { float projectedRadius; float radius; float flod; md3Frame_t *frame; // multiple LODs exist, so compute projected bounding sphere // and use that as a criteria for selecting LOD // checked for a forced lowest LOD if (ent->e.reFlags & REFLAG_FORCE_LOD) { return (tr.currentModel->numLods - 1); } frame = ( md3Frame_t * )((( unsigned char * ) tr.currentModel->model.mdc[0]) + tr.currentModel->model.mdc[0]->ofsFrames); frame += ent->e.frame; radius = RadiusFromBounds(frame->bounds[0], frame->bounds[1]); // testing //if (ent->e.reFlags & REFLAG_ORIENT_LOD) //{ // right now this is for trees, and pushes the lod distance way in. // this is not the intended purpose, but is helpful for the new // terrain level that has loads of trees // radius = radius/2.0f; //} if ((projectedRadius = ProjectRadius(radius, ent->e.origin)) != 0) { float lodscale = r_lodscale->value; if (lodscale > 20) { lodscale = 20; } flod = 1.0f - projectedRadius * lodscale; } else { // object intersects near view plane, e.g. view weapon flod = 0; } flod *= tr.currentModel->numLods; lod = ROUND_INT(flod); if (lod < 0) { lod = 0; } else if (lod >= tr.currentModel->numLods) { lod = tr.currentModel->numLods - 1; } } lod += r_lodbias->integer; if (lod >= tr.currentModel->numLods) { lod = tr.currentModel->numLods - 1; } if (lod < 0) { lod = 0; } return lod; }
/* returns -1 on error, 0 on success */ int init_nonce_count() { unsigned long size; unsigned long max_mem; unsigned orig_array_size; if (nid_crt==0){ BUG("auth: init_nonce_count: nonce index must be " "initialized first (see init_nonce_id())\n"); return -1; } orig_array_size=nc_array_size; if (nc_array_k==0){ if (nc_array_size==0){ nc_array_size=DEFAULT_NC_ARRAY_SIZE; } nc_array_k=bit_scan_reverse32(nc_array_size); } size=1UL<<nc_array_k; /* ROUNDDOWN to 2^nc_array_k */ if (size < MIN_NC_ARRAY_SIZE){ WARN("auth: nonce-count in.flight nonces is very low (%d)," " consider increasing nc_array_size to at least %d\n", orig_array_size, MIN_NC_ARRAY_SIZE); } if (size > MAX_NC_ARRAY_SIZE){ WARN("auth: nonce-count in flight nonces is too high (%d)," " consider decreasing nc_array_size to at least %d\n", orig_array_size, MAX_NC_ARRAY_SIZE); } if (size!=nc_array_size){ if (orig_array_size!=0) INFO("auth: nc_array_size rounded down to %ld\n", size); else INFO("auth: nc_array_size set to %ld\n", size); } max_mem=shm_available(); if (size*sizeof(nc_t) >= max_mem){ ERR("auth: nc_array_size (%ld) is too big for the configured " "amount of shared memory (%ld bytes <= %ld bytes)\n", size, max_mem, size*sizeof(nc_t)); return -1; }else if (size*sizeof(nc_t) >= max_mem/2){ WARN("auth: the currently configured nc_array_size (%ld) " "would use more then 50%% of the available shared" " memory(%ld bytes)\n", size, max_mem); } nc_array_size=size; if (nid_pool_no>=nc_array_size){ ERR("auth: nid_pool_no (%d) too high for the configured " "nc_array_size (%d)\n", nid_pool_no, nc_array_size); return -1; } nc_partition_size=nc_array_size >> nid_pool_k; nc_partition_k=nc_array_k-nid_pool_k; nc_partition_mask=(1<<nc_partition_k)-1; assert(nc_partition_size == nc_array_size/nid_pool_no); assert(1<<(nc_partition_k+nid_pool_k) == nc_array_size); if ((nid_t)nc_partition_size >= ((nid_t)(-1)/NID_INC)){ ERR("auth: nc_array_size too big, try decreasing it or increasing" "the number of pools/partitions\n"); return -1; } if (nc_partition_size < MIN_NC_ARRAY_PARTITION){ WARN("auth: nonce-count in-flight nonces very low," " consider either decreasing nc_pool_no (%d) or " " increasing nc_array_size (%d) such that " "nc_array_size/nid_pool_no >= %d\n", nid_pool_no, orig_array_size, MIN_NC_ARRAY_PARTITION); } /* array size should be multiple of sizeof(unsigned int) since we * access it as an uint array */ nc_array=shm_malloc(sizeof(nc_t)*ROUND_INT(nc_array_size)); if (nc_array==0){ ERR("auth: init_nonce_count: memory allocation failure, consider" " either decreasing nc_array_size of increasing the" " the shared memory ammount\n"); goto error; } /* int the nc_array with the max nc value to avoid replay attacks after * ser restarts (because the nc is already maxed out => no received * nc will be accepted, until the corresponding cell is reset) */ memset(nc_array, 0xff, sizeof(nc_t)*ROUND_INT(nc_array_size)); return 0; error: destroy_nonce_count(); return -1; }
/* allocates memory for a new config script variable * The value of the variable is not set! */ cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type, char *descr) { cfg_group_t *group; cfg_script_var_t *var; int gname_len, vname_len, descr_len; LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname); if (cfg_shmized) { LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, " "the config has been already shmized\n"); return NULL; } gname_len = strlen(gname); vname_len = strlen(vname); /* the group may have been already declared */ group = cfg_lookup_group(gname, gname_len); if (group) { if (group->dynamic == CFG_GROUP_STATIC) { /* the group has been already declared by a module or by the core */ LOG(L_ERR, "ERROR: new_cfg_script_var(): " "configuration group has been already declared: %s\n", gname); return NULL; } /* the dynamic or empty group is found */ /* verify that the variable does not exist */ for ( var = (cfg_script_var_t *)group->vars; var; var = var->next ) { if ((var->name_len == vname_len) && (memcmp(var->name, vname, vname_len) == 0)) { LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n", gname, vname); return NULL; } } if (group->dynamic == CFG_GROUP_UNKNOWN) group->dynamic = CFG_GROUP_DYNAMIC; } else { /* create a new group with NULL values, we will fix it later, when all the variables are known */ group = cfg_new_group(gname, gname_len, 0 /* num */, NULL /* mapping */, NULL /* vars */, 0 /* size */, NULL /* handle */); if (!group) goto error; group->dynamic = CFG_GROUP_DYNAMIC; } switch (type) { case CFG_VAR_INT: group->size = ROUND_INT(group->size); group->size += sizeof(int); break; case CFG_VAR_STR: group->size = ROUND_POINTER(group->size); group->size += sizeof(str); break; default: LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n"); return NULL; } group->num++; if (group->num > CFG_MAX_VAR_NUM) { LOG(L_ERR, "ERROR: new_cfg_script_var(): too many variables (%d) within a single group," " the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group into multiple" " definitions.\n", group->num, CFG_MAX_VAR_NUM); return NULL; } var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t)); if (!var) goto error; memset(var, 0, sizeof(cfg_script_var_t)); var->type = type; /* add the variable to the group */ var->next = (cfg_script_var_t *)(void *)group->vars; group->vars = (char *)(void *)var; /* clone the name of the variable */ var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1)); if (!var->name) goto error; memcpy(var->name, vname, vname_len + 1); var->name_len = vname_len; if (descr) { /* save the description */ descr_len = strlen(descr); var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1)); if (!var->descr) goto error; memcpy(var->descr, descr, descr_len + 1); } return var; error: LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n"); return NULL; }
/* fix-up the dynamically declared group: * - allocate memory for the arrays * - set the values within the memory block */ int cfg_script_fixup(cfg_group_t *group, unsigned char *block) { cfg_mapping_t *mapping = NULL; cfg_def_t *def = NULL; void **handle = NULL; int i, offset; cfg_script_var_t *script_var, *script_var2; str s; mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num); if (!mapping) goto error; memset(mapping, 0, sizeof(cfg_mapping_t)*group->num); /* The variable definition array must look like as if it was declared * in C code, thus, add an additional slot at the end with NULL values */ def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1)); if (!def) goto error; memset(def, 0, sizeof(cfg_def_t)*(group->num + 1)); /* fill the definition and the mapping arrays */ offset = 0; for ( i = 0, script_var = (cfg_script_var_t *)group->vars; script_var; i++, script_var = script_var->next ) { /* there has been already memory allocated for the name */ def[i].name = script_var->name; def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT); def[i].descr = script_var->descr; def[i].min = script_var->min; def[i].max = script_var->max; mapping[i].def = &(def[i]); mapping[i].name_len = script_var->name_len; mapping[i].pos = i; switch (script_var->type) { case CFG_VAR_INT: offset = ROUND_INT(offset); mapping[i].offset = offset; *(int *)(block + offset) = script_var->val.i; offset += sizeof(int); break; case CFG_VAR_STR: offset = ROUND_POINTER(offset); mapping[i].offset = offset; if (cfg_clone_str(&(script_var->val.s), &s)) goto error; memcpy(block + offset, &s, sizeof(str)); mapping[i].flag |= cfg_var_shmized; offset += sizeof(str); break; } } /* allocate a handle even if it will not be used to directly access the variable, like handle->variable cfg_get_* functions access the memory block via the handle to make sure that it is always safe, thus, it must be created */ handle = (void **)pkg_malloc(sizeof(void *)); if (!handle) goto error; *handle = NULL; group->handle = handle; group->mapping = mapping; /* everything went fine, we can free the temporary list */ script_var = (cfg_script_var_t *)group->vars; group->vars = NULL; while (script_var) { script_var2 = script_var->next; if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) pkg_free(script_var->val.s.s); pkg_free(script_var); script_var = script_var2; } return 0; error: if (mapping) pkg_free(mapping); if (def) pkg_free(def); if (handle) pkg_free(handle); LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n"); return -1; }