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; 
        } 
    } 
}
示例#5
0
/*
==============
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
}
示例#6
0
/*
=================
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;
}
示例#7
0
文件: nc.c 项目: BackupTheBerlios/ser
/* 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;
}
示例#8
0
/* 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;
}
示例#9
0
/* 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;
}