site logo  RexxutilSysstemc

HomePage | Categories |* BLOG *| RecentChanges | RecentlyCommented | Login/Register

sysstem.c


This source file contains SysStemSort, SysStemDelete, SysStemInsert, and SysStemCopy.

SysStemSort uses some code from Patrick TJ McPhee's regutil 1.26.

/**************************************************************************
*
*             eCS RexxUtil Library Replacement Project
*
*  Contains the following functions:
*      SysStemSort
*      SysStemDelete
*      SysStemInsert
*      SysStemCopy
*
*  Michael K Greene, December 2007
*
*  SysStemSort from regutil 1.26 by Patrick TJ McPhee - see license concerning
*    this code below
*
------------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
/* Copyright (c) 2005-2006 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* http://www.oorexx.org/license.html                                         */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/******************************************************************************/

#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <alloca.h>

#include <rexxdefs.h>  // rexxsaa.h include in this header


/*********************************************************************/
/* Defines used by SysStemSort -- must match values in okstem.hpp    */
/*********************************************************************/

#define SORT_CASESENSITIVE 0
#define SORT_CASEIGNORE    1

#define SORT_ASCENDING     0
#define SORT_DECENDING     1

RexxFunctionHandler SysStemDelete;
RexxFunctionHandler SysStemInsert;
RexxFunctionHandler SysStemCopy;
RexxFunctionHandler SysStemSort;


/*************************************************************************
* Function:  SysStemDelete                                               *
*                                                                        *
* Syntax:    result = SysStemDelete(stem, startitem [,itemcount])        *
*                                                                        *
* Params:    stem - name of stem where item will be deleted              *
*            startitem - index of item to delete                         *
*            itemcount - number of items to delete if more than 1        *
*                                                                        *
* Return:    0 - delete was successful                                   *
*            -1 - delete failed                                          *
*************************************************************************/

unsigned long SysStemDelete(unsigned char *name,
						   unsigned long numargs,
						   RXSTRING args[],
						   char *queuename,
						   RXSTRING *retstr)
{
	unsigned long   rc;
	char            szStemName[255];
	char            *pszStemIdx;
	char            szValue[255];
	SHVBLOCK        shvb;
	unsigned long   ulIdx;
	unsigned long   ulFirst;
	unsigned long   ulItems = 1;
	unsigned long   ulCount;
	bool            fOk = TRUE;

	if ( (numargs < 2) || (numargs > 3) || /* validate arguments       */
		!RXVALIDSTRING(args[0]) || !RXVALIDSTRING(args[1]) ||
		((numargs == 3) && !RXVALIDSTRING(args[2])) )
	  return INVALID_ROUTINE;

	/* remember stem name */
	memset(szStemName, 0, sizeof(szStemName));
	strcpy(szStemName, args[0].strptr);

	if (szStemName[args[0].strlength-1] != '.') szStemName[args[0].strlength] = '.';
	pszStemIdx = &(szStemName[strlen(szStemName)]);

	/* get item index to be deleted */
	if (sscanf(args[1].strptr, "%ld", &ulFirst) != 1) return INVALID_ROUTINE;

	/* get number of items to delete */
	if (numargs == 3) {
		if (sscanf(args[2].strptr, "%ld", &ulItems) != 1) return INVALID_ROUTINE;
		if (ulItems == 0) return INVALID_ROUTINE;
	} /* endif */

	/* retrieve the number of elements in stem */
	strcpy(pszStemIdx, "0");
	shvb.shvnext = NULL;
	shvb.shvname.strptr = szStemName;
	shvb.shvname.strlength = strlen((const char *)szStemName);
	shvb.shvvalue.strptr = szValue;
	shvb.shvvalue.strlength = sizeof(szValue);
	shvb.shvnamelen = shvb.shvname.strlength;
	shvb.shvvaluelen = shvb.shvvalue.strlength;
	shvb.shvcode = RXSHV_SYFET;
	shvb.shvret = 0;

	if (RexxVariablePool(&shvb) == RXSHV_OK) {
		/* index retrieved fine */
		if (sscanf(shvb.shvvalue.strptr, "%ld", &ulCount) != 1) return INVALID_ROUTINE;

		/* check wether supplied index and count is within limits */
		if (ulFirst + ulItems - 1 > ulCount) return INVALID_ROUTINE;

		/* now copy the remaining indices up front */
		for (ulIdx = ulFirst; ulIdx + ulItems <= ulCount; ulIdx++) {

			/* get element to relocate */
			sprintf(pszStemIdx, "%ld", ulIdx + ulItems);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szStemName;
			shvb.shvname.strlength = strlen((const char *)szStemName);
			shvb.shvvalue.strptr = NULL;
			shvb.shvvalue.strlength = 0;
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYFET;
			shvb.shvret = 0;

			if (RexxVariablePool(&shvb) == RXSHV_OK) {
				sprintf(pszStemIdx, "%ld", ulIdx);
				shvb.shvnext = NULL;
				shvb.shvname.strptr = szStemName;
				shvb.shvname.strlength = strlen((const char *)szStemName);
				shvb.shvnamelen = shvb.shvname.strlength;
				shvb.shvvaluelen = shvb.shvvalue.strlength;
				shvb.shvcode = RXSHV_SYSET;
				shvb.shvret = 0;

				rc = RexxVariablePool(&shvb);

				if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;

				/* free memory allocated by REXX */
				DosFreeMem(shvb.shvvalue.strptr);
			} else fOk = FALSE;

			if (!fOk) break;
		} /* endfor */

		if (fOk) {
			/* now delete the items at the end */
			for (ulIdx = ulCount - ulItems + 1; ulIdx <= ulCount; ulIdx++) {
				sprintf(pszStemIdx, "%ld", ulIdx);
				shvb.shvnext = NULL;
				shvb.shvname.strptr = szStemName;
				shvb.shvname.strlength = strlen((const char *)szStemName);
				shvb.shvvalue.strptr = NULL;
				shvb.shvvalue.strlength = 0;
				shvb.shvnamelen = shvb.shvname.strlength;
				shvb.shvvaluelen = shvb.shvvalue.strlength;
				shvb.shvcode = RXSHV_SYDRO;
				shvb.shvret = 0;

				if (RexxVariablePool(&shvb) != RXSHV_OK) {
					fOk = FALSE;
					break;
				} /* endif */
			} /* endfor */
		} /* endif */

		if (fOk) {
			/* set the new number of items in the stem array */
			strcpy(pszStemIdx, "0");
			sprintf(szValue, "%ld", ulCount - ulItems);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szStemName;
			shvb.shvname.strlength = strlen((const char *)szStemName);
			shvb.shvvalue.strptr = szValue;
			shvb.shvvalue.strlength = strlen(szValue);
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYSET;
			shvb.shvret = 0;

			rc = RexxVariablePool(&shvb);

			if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;
		} /* endif */

	} else fOk = FALSE;


	if (fOk) RETVAL(0)
	else RETVAL(-1)
}


/*************************************************************************
* Function:  SysStemInsert                                               *
*                                                                        *
* Syntax:    result = SysStemInsert(stem, position, value)               *
*                                                                        *
* Params:    stem - name of stem where item will be inserted             *
*            position - index where new item will be inserted            *
*            value - new item value                                      *
*                                                                        *
* Return:    0 - insert was successful                                   *
*            -1 - insert failed                                          *
*************************************************************************/

unsigned long SysStemInsert(unsigned char *name,
						   unsigned long numargs,
						   RXSTRING args[],
						   char *queuename,
						   RXSTRING *retstr)
{
	unsigned long   rc;
	char            szStemName[255];
	char            *pszStemIdx;
	char            szValue[255];
	SHVBLOCK        shvb;
	unsigned long   ulIdx;
	unsigned long   ulPosition;
	unsigned long   ulCount;
	bool            fOk = TRUE;

	if ( (numargs != 3) ||  /* validate arguments       */
		!RXVALIDSTRING(args[0]) || !RXVALIDSTRING(args[1]) ||
		RXNULLSTRING(args[2]) )
	  return INVALID_ROUTINE;

	/* remember stem name */
	memset(szStemName, 0, sizeof(szStemName));
	strcpy(szStemName, args[0].strptr);

	if (szStemName[args[0].strlength-1] != '.') szStemName[args[0].strlength] = '.';
	pszStemIdx = &(szStemName[strlen(szStemName)]);

	/* get new item index */
	if (sscanf(args[1].strptr, "%ld", &ulPosition) != 1) return INVALID_ROUTINE;

	/* retrieve the number of elements in stem */
	strcpy(pszStemIdx, "0");
	shvb.shvnext = NULL;
	shvb.shvname.strptr = szStemName;
	shvb.shvname.strlength = strlen((const char *)szStemName);
	shvb.shvvalue.strptr = szValue;
	shvb.shvvalue.strlength = sizeof(szValue);
	shvb.shvnamelen = shvb.shvname.strlength;
	shvb.shvvaluelen = shvb.shvvalue.strlength;
	shvb.shvcode = RXSHV_SYFET;
	shvb.shvret = 0;
	if (RexxVariablePool(&shvb) == RXSHV_OK) {
		/* index retrieved fine */
		if (sscanf(shvb.shvvalue.strptr, "%ld", &ulCount) != 1) return INVALID_ROUTINE;

		/* check wether new position is within limits */
		if ((ulPosition == 0) || (ulPosition > ulCount + 1)) return INVALID_ROUTINE;

		/* make room for new item by moving all items to the end */
		for (ulIdx = ulCount; ulIdx >= ulPosition; ulIdx--) {
			/* get element to relocate */
			sprintf(pszStemIdx, "%ld", ulIdx);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szStemName;
			shvb.shvname.strlength = strlen((const char *)szStemName);
			shvb.shvvalue.strptr = NULL;
			shvb.shvvalue.strlength = 0;
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYFET;
			shvb.shvret = 0;

			if (RexxVariablePool(&shvb) == RXSHV_OK) {
				sprintf(pszStemIdx, "%ld", ulIdx + 1);
				shvb.shvnext = NULL;
				shvb.shvname.strptr = szStemName;
				shvb.shvname.strlength = strlen((const char *)szStemName);
				shvb.shvnamelen = shvb.shvname.strlength;
				shvb.shvvaluelen = shvb.shvvalue.strlength;
				shvb.shvcode = RXSHV_SYSET;
				shvb.shvret = 0;

				rc = RexxVariablePool(&shvb);

				if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;

				/* free memory allocated by REXX */
				DosFreeMem(shvb.shvvalue.strptr);
			} else fOk = FALSE;

			if (!fOk) break;
		} /* endfor */

		if (fOk) {
			/* set the new item value */
			sprintf(pszStemIdx, "%ld", ulPosition);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szStemName;
			shvb.shvname.strlength = strlen((const char *)szStemName);
			shvb.shvvalue.strptr = args[2].strptr;
			shvb.shvvalue.strlength = args[2].strlength;
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYSET;
			shvb.shvret = 0;

			rc = RexxVariablePool(&shvb);

			if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;
		} /* endif */

		if (fOk) {
			/* set the new number of items in the stem array */
			strcpy(pszStemIdx, "0");
			sprintf(szValue, "%ld", ulCount + 1);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szStemName;
			shvb.shvname.strlength = strlen((const char *)szStemName);
			shvb.shvvalue.strptr = szValue;
			shvb.shvvalue.strlength = strlen(szValue);
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYSET;
			shvb.shvret = 0;

			rc = RexxVariablePool(&shvb);

			if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;
		} /* endif */
	} else fOk = FALSE;

	if (fOk) RETVAL(0)
	else RETVAL(-1)
}


/*************************************************************************
* Function:  SysStemCopy                                                 *
*                                                                        *
* Syntax:    result = SysStemCopy(fromstem, tostem, from, to, count      *
*                                 [,insert])                             *
*                                                                        *
* Params:    fromstem - name of source stem                              *
*            tostem - - name of target stem                              *
*            from  - first index in source stem to copy                  *
*            to - position where items are copied/inserted in target stem*
*            count - number of items to copy/insert                      *
*            insert - 'I' to indicate insert instead of 'O' overwrite    *
*                                                                        *
* Return:    0 - stem copy was successful                                *
*            -1 - stem copy failed                                       *
*************************************************************************/

unsigned long SysStemCopy(unsigned char *name,
						   unsigned long numargs,
						   RXSTRING args[],
						   char *queuename,
						   RXSTRING *retstr)
{
	unsigned long rc;
	char          szFromStemName[255];
	char          szToStemName[255];
	char          *pszFromStemIdx;
	char          *pszToStemIdx;
	char          szValue[255];
	SHVBLOCK      shvb;
	unsigned long ulIdx;
	unsigned long ulToCount;
	unsigned long ulFromCount;
	unsigned long ulFrom = 1;
	unsigned long ulTo = 1;
	unsigned long ulCopyCount = 0;
	bool          fInsert = FALSE;
	bool          fOk = TRUE;

	if ( (numargs < 2) || (numargs > 6) ||  /* validate arguments      */
		!RXVALIDSTRING(args[0]) || !RXVALIDSTRING(args[1]) ||
		((numargs == 6) && !RXVALIDSTRING(args[5])) )
	  return INVALID_ROUTINE;

	/* remember stem names */
	memset(szFromStemName, 0, sizeof(szFromStemName));
	strcpy(szFromStemName, args[0].strptr);

	if (szFromStemName[args[0].strlength-1] != '.')
		szFromStemName[args[0].strlength] = '.';

	pszFromStemIdx = &(szFromStemName[strlen(szFromStemName)]);

	memset(szToStemName, 0, sizeof(szToStemName));
	strcpy(szToStemName, args[1].strptr);

	if (szToStemName[args[1].strlength-1] != '.')
		szToStemName[args[1].strlength] = '.';

	pszToStemIdx = &(szToStemName[strlen(szToStemName)]);

	/* get from item index */
	if ((numargs >= 3) && RXVALIDSTRING(args[2]))
		if (sscanf(args[2].strptr, "%ld", &ulFrom) != 1)
			return INVALID_ROUTINE;

	/* get to item index */
	if ((numargs >= 4) && RXVALIDSTRING(args[3]))
		if (sscanf(args[3].strptr, "%ld", &ulTo) != 1)
			return INVALID_ROUTINE;

	/* get copy count */
	if ((numargs >= 5) && RXVALIDSTRING(args[4]))
		if (sscanf(args[4].strptr, "%ld", &ulCopyCount) != 1)
			return INVALID_ROUTINE;

	/* get copy type */
	if (numargs >= 6) {
		switch (args[5].strptr[0]) {

		case 'I':
		case 'i':
			fInsert = TRUE;
			break;

		case 'O':
		case 'o':
			fInsert = FALSE;
			break;

		default:
			return INVALID_ROUTINE;
		} /* endswitch */
	} /* endif */

	/* retrieve the number of elements in stems */
	strcpy(pszFromStemIdx, "0");
	shvb.shvnext = NULL;
	shvb.shvname.strptr = szFromStemName;
	shvb.shvname.strlength = strlen((const char *)szFromStemName);
	shvb.shvvalue.strptr = szValue;
	shvb.shvvalue.strlength = sizeof(szValue);
	shvb.shvnamelen = shvb.shvname.strlength;
	shvb.shvvaluelen = shvb.shvvalue.strlength;
	shvb.shvcode = RXSHV_SYFET;
	shvb.shvret = 0;

	if (RexxVariablePool(&shvb) == RXSHV_OK) {
		/* index retrieved fine */
		if (sscanf(shvb.shvvalue.strptr, "%ld", &ulFromCount) != 1)
			return INVALID_ROUTINE;

		if ((ulCopyCount > (ulFromCount - ulFrom + 1)) || (ulFromCount == 0))
			return INVALID_ROUTINE;
	} else fOk = FALSE;

	if (fOk) {
		strcpy(pszToStemIdx, "0");
		shvb.shvnext = NULL;
		shvb.shvname.strptr = szToStemName;
		shvb.shvname.strlength = strlen((const char *)szToStemName);
		shvb.shvvalue.strptr = szValue;
		shvb.shvvalue.strlength = sizeof(szValue);
		shvb.shvnamelen = shvb.shvname.strlength;
		shvb.shvvaluelen = shvb.shvvalue.strlength;
		shvb.shvcode = RXSHV_SYFET;
		shvb.shvret = 0;
		rc = RexxVariablePool(&shvb);

		if (rc == RXSHV_OK) {
			/* index retrieved fine */
			if (sscanf(shvb.shvvalue.strptr, "%ld", &ulToCount) != 1)
				return INVALID_ROUTINE;
		} else {
			if (rc == RXSHV_NEWV) {
				/* tostem.0 is not set, we assume empty target stem */
				ulToCount = 0;
			} else fOk = FALSE;
		} /* endif */

		if (fOk) {
			if (ulTo > ulToCount + 1) return INVALID_ROUTINE;
		} /* endif */
	} /* endif */

	/* set copy count to number of items in source stem if not already set */
	if (ulCopyCount == 0) ulCopyCount = ulFromCount - ulFrom + 1;

	if (fOk && fInsert) {
		/* if we are about to insert the items we have to make room */
		for (ulIdx = ulToCount; ulIdx >= ulTo; ulIdx--) {
			/* get element to relocate */
			sprintf(pszToStemIdx, "%ld", ulIdx);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szToStemName;
			shvb.shvname.strlength = strlen((const char *)szToStemName);
			shvb.shvvalue.strptr = NULL;
			shvb.shvvalue.strlength = 0;
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYFET;
			shvb.shvret = 0;

			if (RexxVariablePool(&shvb) == RXSHV_OK) {
				sprintf(pszToStemIdx, "%ld", ulIdx + ulCopyCount);
				shvb.shvnext = NULL;
				shvb.shvname.strptr = szToStemName;
				shvb.shvname.strlength = strlen((const char *)szToStemName);
				shvb.shvnamelen = shvb.shvname.strlength;
				shvb.shvvaluelen = shvb.shvvalue.strlength;
				shvb.shvcode = RXSHV_SYSET;
				shvb.shvret = 0;
				rc = RexxVariablePool(&shvb);
				if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;

				/* free memory allocated by REXX */
				DosFreeMem(shvb.shvvalue.strptr);
			} else fOk = FALSE;

			if (!fOk) break;

		} /* endfor */

		if (fOk) {
			/* set the new count for the target stem */
			strcpy(pszToStemIdx, "0");
			ulToCount += ulCopyCount;
			sprintf(szValue, "%ld", ulToCount);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szToStemName;
			shvb.shvname.strlength = strlen((const char *)szToStemName);
			shvb.shvvalue.strptr = szValue;
			shvb.shvvalue.strlength = strlen(szValue);
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYSET;
			shvb.shvret = 0;
			rc = RexxVariablePool(&shvb);
			if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;
		} /* endif */
	} /* endif */

	if (fOk) {
		/* now do the actual copying from the source to target */
		for (ulIdx = 0; ulIdx < ulCopyCount; ulIdx++) {
			/* get element to copy */
			sprintf(pszFromStemIdx, "%ld", ulFrom + ulIdx);
			shvb.shvnext = NULL;
			shvb.shvname.strptr = szFromStemName;
			shvb.shvname.strlength = strlen((const char *)szFromStemName);
			shvb.shvvalue.strptr = NULL;
			shvb.shvvalue.strlength = 0;
			shvb.shvnamelen = shvb.shvname.strlength;
			shvb.shvvaluelen = shvb.shvvalue.strlength;
			shvb.shvcode = RXSHV_SYFET;
			shvb.shvret = 0;

			if (RexxVariablePool(&shvb) == RXSHV_OK) {
				sprintf(pszToStemIdx, "%ld", ulTo + ulIdx);
				shvb.shvnext = NULL;
				shvb.shvname.strptr = szToStemName;
				shvb.shvname.strlength = strlen((const char *)szToStemName);
				shvb.shvnamelen = shvb.shvname.strlength;
				shvb.shvvaluelen = shvb.shvvalue.strlength;
				shvb.shvcode = RXSHV_SYSET;
				shvb.shvret = 0;
				rc = RexxVariablePool(&shvb);

				if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;

				/* free memory allocated by REXX */
				DosFreeMem(shvb.shvvalue.strptr);
			} else fOk = FALSE;

			if (!fOk) break;
		} /* endfor */
	} /* endif */

	if (fOk && (ulTo + ulCopyCount - 1 > ulToCount)) {
		/* set the new count for the target stem */
		strcpy(pszToStemIdx, "0");
		ulToCount = ulTo + ulCopyCount - 1;
		sprintf(szValue, "%ld", ulToCount);
		shvb.shvnext = NULL;
		shvb.shvname.strptr = szToStemName;
		shvb.shvname.strlength = strlen((const char *)szToStemName);
		shvb.shvvalue.strptr = szValue;
		shvb.shvvalue.strlength = strlen(szValue);
		shvb.shvnamelen = shvb.shvname.strlength;
		shvb.shvvaluelen = shvb.shvvalue.strlength;
		shvb.shvcode = RXSHV_SYSET;
		shvb.shvret = 0;
		rc = RexxVariablePool(&shvb);

		if ((rc != RXSHV_OK) && (rc != RXSHV_NEWV)) fOk = FALSE;
	} /* endif */

	if (fOk) RETVAL(0)
	else RETVAL(-1)
}


/*************************************************************************
* Function:  SysStemSort                                                 *
*                                                                        *
* Syntax:    result = SysStemSort(stem, order, type, start, end,         *
*                                 firstcol, lastcol)                     *
*                                                                        *
* Params:    stem - name of stem to sort                                 *
*            order - 'A' or 'D' for sort order                           *
*            type - 'C', 'I', 'N' for comparision type                   *
*            start - first index to sort                                 *
*            end - last index to sort                                    *
*            firstcol - first column to use as sort key                  *
*            lastcol - last column to use as sort key                    *
*                                                                        *
* Return:    0 - sort was successful                                     *
*            -1 - sort failed                                            *
*************************************************************************/
/* Stem and variable manipulation functions for regutil
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is regutil.
 *
 * The Initial Developer of the Original Code is Patrick TJ McPhee.
 * Portions created by Patrick McPhee are Copyright . 1998, 2001
 * Patrick TJ McPhee. All Rights Reserved.
 *
 * Contributors:
 *
 * $Header: C:/ptjm/rexx/regutil/RCS/regstem.c 1.21 2004/06/16 00:15:06 ptjm Rel $
 */

/* return codes. 22 is rc for invalid call */
#define NOMEMORY 5
#define BADARGS 22
#define BADGENERAL 40

#define INITPTR 1000

/* make a null-terminated string from a rexx string */
#define rxstrdup(y, x) do { \
	y = (char *)alloca(RXSTRLEN(x)+1); \
	memcpy(y,RXSTRPTR(x),RXSTRLEN(x)); \
	y[RXSTRLEN(x)] = 0; \
	} while (0)

/* datatype: re-sizeable array of characters */
struct caalloc {
   struct caalloc * N;
   int alloc, used;
   char data[sizeof(int)];
};

typedef struct {
	int count;
	int ptr_alloc;
	PRXSTRING array;
	struct caalloc * chars;
} chararray;

// stemsort helpers from regutil 1.26
static int rxstrcasecmp(const PRXSTRING l, const PRXSTRING r);
static int rxstrcasecmpbackwards(const PRXSTRING l, const PRXSTRING r);
static int rxstrcmp(const PRXSTRING l, const PRXSTRING r);
static int rxstrcmpbackwards(const PRXSTRING l, const PRXSTRING r);
static int casecmp(const unsigned char * l, const unsigned char * r, const int len);
static int getstemtail(PRXSTRING varname, const int ind, chararray * const values);
static int setastem(PRXSTRING varname, const chararray * const values);
static int cha_addstr(chararray *ca, const char * str, int len);
static chararray * new_chararray(void);
static void delete_chararray(chararray * );


unsigned long SysStemSort(unsigned char *name,
						   unsigned long numargs,
						   RXSTRING args[],
						   char *queuename,
						   RXSTRING *retstr)
{
	char          stemName[255];
	size_t        first     = 1;
	size_t        last      = ULONG_MAX;
	size_t        firstCol  = 0;
	size_t        lastCol   = ULONG_MAX;
	int           sortType  = SORT_CASESENSITIVE;
	int           sortOrder = SORT_ASCENDING;

	// regutil varables
	chararray * ca;
	int start       = 0;
	int count       = 0;
	int width       = 0;
	register int i;
	int (*cmpfn)(const PRXSTRING l, const PRXSTRING r);


	// quick check valid number of args
	if ( (numargs < 1) || (numargs > 7) || !RXVALIDSTRING(args[0]))
		RETVAL(-1) // return INVALID_ROUTINE;

	/* remember stem name */
	memset(stemName, 0, sizeof(stemName));
	strcpy(stemName, args[0].strptr);

	// check for trailing '.' and add if not provided
	if (stemName[args[0].strlength-1] != '.') stemName[args[0].strlength] = '.';

	/* check other parameters */

	// [ORDER option] Decode option of order as Ascending or Decending
	if ((numargs >= 2) && RXVALIDSTRING(args[1])) {  /* sort order  */

		switch (args[1].strptr[0]) {

		case 'A':
		case 'a':
			sortOrder = SORT_ASCENDING;
			break;

		case 'D':
		case 'd':
			sortOrder = SORT_DECENDING;
			break;

		default:
			return INVALID_ROUTINE;
		} /* endswitch */
	} /* endif */

	// [TYPE option] Decode option as Case sensitive or insensitive
	if ((numargs >= 3) && RXVALIDSTRING(args[2])) {  /* sort type */

		switch (args[2].strptr[0]) {

		case 'C':
		case 'c':
			sortType = SORT_CASESENSITIVE;
			break;

		case 'I':
		case 'i':
			sortType = SORT_CASEIGNORE;
			break;

		default:
			return INVALID_ROUTINE;
		} /* endswitch */
	} /* endif */

	// scan the [START option] into size_t first
	if ((numargs >= 4) && RXVALIDSTRING(args[3])) { /* first element to sort */
		if (sscanf(args[3].strptr, "%ld", &first) != 1) return INVALID_ROUTINE;
		if (first == 0) return INVALID_ROUTINE; // can't use 0 index
	} /* endif */

	// scan the [END option] into size_t last
	if ((numargs >= 5) && RXVALIDSTRING(args[4])) { /* last element to sort */
		if (sscanf(args[4].strptr, "%ld", &last) != 1) return INVALID_ROUTINE;
		if (last < first) return INVALID_ROUTINE;
	} /* endif */

	// scan the [FIRSTCOL option] into size_t firstCol then subtract 1
	if ((numargs >= 6) && RXVALIDSTRING(args[5])) { /* first column to sort */
		if (sscanf(args[5].strptr, "%ld", &firstCol) != 1) return INVALID_ROUTINE;
		firstCol--;
	} /* endif */

	// scan the [LASTCOL option] into size_t lastCol then subtract 1
	if ((numargs == 7) && RXVALIDSTRING(args[6])) { /* last column to sort */
		if (sscanf(args[6].strptr, "%ld", &lastCol) != 1) return INVALID_ROUTINE;
		lastCol--;
		if (lastCol < firstCol) RETVAL(-7) //return INVALID_ROUTINE;
	} /* endif */


	// *** here is where the stemsort OREXX sources moves into regutil source
	start = (first - 1); //TMP
	if(start < 0) return INVALID_ROUTINE;

	count = last - first;
	if (count < 0) count = 0;  //RETVAL(-9) //return INVALID_ROUTINE;

	width = lastCol - firstCol;

	ca = new_chararray();
	if (!ca) return NOMEMORY;

	getstemtail(args, 1, ca);

	if (!count) {
		count = ca->count - start;
		if (count < 0) count = 0;
	}

	if (sortType && sortOrder) cmpfn = rxstrcasecmpbackwards;
	else if (sortType) cmpfn = rxstrcasecmp;
	else if (sortOrder) cmpfn = rxstrcmpbackwards;
	else cmpfn = rxstrcmp;

	if (!firstCol && !width)
	  qsort(ca->array+start, count, sizeof(*ca->array), (int(*)(const void *, const void *))cmpfn);
	else {

		struct {
			RXSTRING se;
			RXSTRING orig;
		} *aa;

		aa = malloc(sizeof(*aa) * count);



		if (!aa) {
			delete_chararray(ca);
			return NOMEMORY;
		}

		for (i = 0; i < count; i++) {
			aa[i].orig = ca->array[i+start];
			aa[i].se.strptr = aa[i].orig.strptr + firstCol;
			aa[i].se.strlength = aa[i].orig.strlength - firstCol;

			if (width && (int)aa[i].se.strlength > width) aa[i].se.strlength = width;

			else if ((int)aa[i].se.strlength < 0) aa[i].se.strlength = 0;
	  }

	  qsort(aa, count, sizeof(*aa), (int(*)(const void *, const void *))cmpfn);

	  for (i = 0; i < count; i++) {
		 ca->array[i+start] = aa[i].orig;
	  }

	  free(aa);
   }

	setastem(args, ca);
	delete_chararray(ca);

	RETVAL(0)
}


static int rxstrcasecmpbackwards(const PRXSTRING l, const PRXSTRING r)
{
	return rxstrcasecmp(r, l);
}


static int rxstrcmpbackwards(const PRXSTRING l, const PRXSTRING r)
{
	return rxstrcmp(r, l);
}


/* compare two strings case-sensitively */
static int rxstrcmp(const PRXSTRING l, const PRXSTRING r)
{
	register int len = min(l->strlength, r->strlength),
						   d = l->strlength - r->strlength,
						   c = memcmp(l->strptr, r->strptr, len);

	return c ? c : d;
}


/* compare two strings case-insensitively */
static int rxstrcasecmp(const PRXSTRING l, const PRXSTRING r)
{
	register int len = min(l->strlength, r->strlength),
						   d = l->strlength - r->strlength,
						   c = casecmp(l->strptr, r->strptr, len);

	return (len && c) ? c : d;
}


/* case-insensitive comparison of two regions of memory */
static int casecmp(const unsigned char * l, const unsigned char * r, const int len)
{
	register int i;
	register int c;

	for (i = c = 0; !c && i < len; i++) c = toupper(l[i]) - toupper(r[i]);

	return c;
}


/* given a stem name, retrieve the values associated with that stem, starting
 * at index ind (1-based) and stick them in a chararray. I'm doing this by
 * retrieving one value at a time and adding it to the array using cha_addstr. */
static int getstemtail(PRXSTRING varname, const int ind, chararray * const values)
{
	SHVBLOCK stem;
	SHVBLOCK *vars;

	register int i;
	register int count;
	register int vallen;

	int namelen = varname->strlength + 12;

	char * origname;
	char valbuf[11];
	char *nameptr;
	char *valptr = NULL;

	if (!values) return -1;

	values->count = 0;

	if (varname->strptr[varname->strlength-1] == '.') {
		rxstrdup(origname, *varname);
	} else {
		origname = alloca(varname->strlength+2);
		memcpy(origname, varname->strptr, varname->strlength);
		origname[varname->strlength] = '.';
		origname[varname->strlength+1] = 0;
	}
	strupr(origname);

	/* first, find out how many there are */
	nameptr = alloca(namelen);
	memset(&stem, 0, sizeof(stem));

	/* set up the .0 member */
	stem.shvname.strptr = nameptr;
	stem.shvname.strlength = sprintf(nameptr, "%s%d", origname, 0);
	stem.shvvalue.strptr = valbuf;
	stem.shvvalue.strlength = stem.shvvaluelen = sizeof(valbuf);
	stem.shvcode = RXSHV_SYFET;

	RexxVariablePool(&stem);

	/* there is no stem, so there is nothing to return */
	if (stem.shvret & RXSHV_NEWV) return 0;

	valbuf[stem.shvvalue.strlength] = 0;
	count = atoi(valbuf) - ind + 1;

	/* likewise, if there is nothing to return, there is nothing
	 * to return */
	if (count <= 0) return 0;

	vallen = 500;
	vars = malloc(count*(sizeof(*vars)+namelen+vallen));

	if (!vars) {
		stem.shvname.strptr = nameptr;
		stem.shvcode = RXSHV_SYFET;
		vallen = 10000;
		valptr = malloc(vallen);
		stem.shvvalue.strptr = valptr;

		for (i = 0; i < count; i++) {
			stem.shvname.strlength = sprintf(nameptr, "%s%d", origname, i+ind);
			stem.shvvaluelen = stem.shvvalue.strlength = vallen;
			RexxVariablePool(&stem);
			if (stem.shvret & RXSHV_TRUNC) {
				vallen = stem.shvvaluelen;
				valptr = realloc(valptr, vallen);
				stem.shvret = 0;
				stem.shvvalue.strptr = valptr;
				i--;
			} else {
				cha_addstr(values, stem.shvvalue.strptr, stem.shvvalue.strlength);
			}
		}
	} else {
		valptr = (char *)(vars+count) + namelen*count;
		for (i = 0; i < count; i++) {
			nameptr = (char *)(vars+count) + namelen*i;
			vars[i].shvname.strptr = nameptr;
			vars[i].shvcode = RXSHV_SYFET;
			vars[i].shvvalue.strptr = valptr+i*vallen;
			vars[i].shvvaluelen = vallen;
			vars[i].shvret = 0;
			vars[i].shvname.strlength = sprintf(nameptr, "%s%d", origname, i+ind);
			vars[i].shvvaluelen = vars[i].shvvalue.strlength = vallen;
			vars[i].shvnext = vars+i+1;
		} vars[i-1].shvnext = NULL;
		valptr = NULL;

		RexxVariablePool(vars);

		/* add strings to array. If any string is truncated, knock up the
		 * buffer and try it again */
		for (i = 0; i < count; i++) {
			if (vars[i].shvret & RXSHV_TRUNC) {
				vars[i].shvnext = NULL;

				/* re-allocate only if we haven't already made the buffer big
				 * enough */
				if (vallen < vars[i].shvvaluelen) {
					vallen = vars[i].shvvaluelen;
					valptr = realloc(valptr, vallen);
				}

				vars[i].shvvalue.strptr = valptr;
				vars[i].shvvaluelen = vallen;
				RexxVariablePool(vars+i);
			}

			cha_addstr(values, vars[i].shvvalue.strptr, vars[i].shvvalue.strlength);
		}
		free(vars);
	}

	if (valptr) free(valptr);

	return 0;
}


/* given an array of strings and the name of a stem variable, set the stem
 * variable to match the strings */
static int setastem(PRXSTRING varname, const chararray * const values)
{
	SHVBLOCK *astem;
	SHVBLOCK stem0[2];
	register int i;
	int namelen = varname->strlength + 12, orignamelen, count;
	char *namebuf;
	char *origname;
	char valbuf[11];
	char *nameptr;

	namebuf = malloc(namelen * (values->count+1));

	if (values && values->count) {
		count = values->count;
		astem = malloc(values->count*sizeof(*astem));
		memset(astem, 0, values->count * sizeof(*astem));
	} else {
	   astem = NULL;
	   count = 0;
	}

	memset(stem0, 0, sizeof(stem0));

	if (varname->strptr[varname->strlength-1] == '.') {
	   rxstrdup(origname, *varname);
	   orignamelen = varname->strlength;
	} else {
	   origname = alloca(varname->strlength+2);
	   memcpy(origname, varname->strptr, varname->strlength);
	   origname[varname->strlength] = '.';
	   origname[varname->strlength+1] = 0;
	   orignamelen = varname->strlength+1;
	}
	strupr(origname);
	nameptr = namebuf;

	/* drop the stem */
	stem0[0].shvnext = stem0+1;
	stem0[0].shvname.strptr = origname;
	stem0[0].shvname.strlength = orignamelen;
	stem0[0].shvcode = RXSHV_DROPV;

	/* set up the .0 member */
	stem0[1].shvnext = astem;
	stem0[1].shvname.strptr = nameptr;
	stem0[1].shvname.strlength = sprintf(nameptr, "%s%d", origname, 0);
	stem0[1].shvvalue.strptr = valbuf;
	stem0[1].shvvalue.strlength = sprintf(valbuf, "%d", count);
	stem0[1].shvcode = RXSHV_SYSET;

	nameptr += namelen;

	for (i = 0; i < count; i++) {
		astem[i].shvnext = astem+i+1;
		astem[i].shvname.strptr = nameptr;
		astem[i].shvname.strlength = sprintf(nameptr, "%s%d", origname, i+1);
		astem[i].shvvalue = values->array[i];
		astem[i].shvcode = RXSHV_SYSET;
		nameptr += namelen;
	}

	if (i) astem[i-1].shvnext = NULL;

	RexxVariablePool(stem0);
	free(namebuf);
	if (astem) free(astem);

	return 0;
}


static chararray * new_chararray(void)
{
	chararray * ca;

	ca = malloc(sizeof(*ca));

	if (!ca)
		return NULL;

	/* allocate 1000 pointers by default. These point into one big buffer,
	 * which we allocate separately from the points -- a chararray has four
	 * mallocs, instead of one per pointer (on the other hand, we'll have
	 * some big chunks of data to realloc ...) */
	ca->ptr_alloc = INITPTR;
	ca->array = malloc(INITPTR*sizeof(*ca->array));
	ca->chars = malloc(sizeof(*ca->chars) + INITPTR*_MAX_PATH);

	if (!ca->chars || !ca->array) {
		if (ca->chars) free(ca->chars);
		if (ca->array) free(ca->array);
		free(ca);
		ca = NULL;
	}

	ca->chars->alloc = INITPTR*_MAX_PATH;
	ca->chars->N = NULL;
	ca->count = 0;
	ca->chars->used = 0;

	return ca;
}


static void free_caalloc(struct caalloc * nd)
{
   if (!nd) return;
   free_caalloc(nd->N);
   free(nd);
}


static void delete_chararray(chararray * ca)
{
	if (!ca) return;

	if (ca->array) free(ca->array);
	free_caalloc(ca->chars);
	free(ca);
}


static int cha_addstr(chararray *ca, const char * str, int len)
{
	if (ca->count >= ca->ptr_alloc) {
		ca->ptr_alloc += INITPTR;
		ca->array = realloc(ca->array, ca->ptr_alloc*sizeof(*ca->array));
		if (ca->array == NULL) {
			ca->ptr_alloc = 0;
			ca->count = 0;
			return -1;
		 }
	}

	/* there's not enough room in this buffer, so allocate a new one which
	 * is big enough */
	if ((ca->chars->used+len+1) >= ca->chars->alloc) {
		struct caalloc * nd, *cd, *pd;

		/* keep the list of buffers ordered by free space -- this prevents some
		 * needless memory allocation at the cost of a few cycles. This doesn't
		 * seem to buy much, but reallocation is generally rare in any case. */
		for (cd = ca->chars, nd = cd->N, pd = NULL;
			 nd && (nd->alloc - nd->used) > (cd->alloc - cd->used);
			 pd = nd, nd = nd->N)
		   ;

		if (pd) {
		   ca->chars = cd->N;
		   cd->N = pd->N;
		   pd->N = cd;
		}

		/* maybe we now have enough space, so test again */
		if ((ca->chars->used+len+1) >= ca->chars->alloc) {
		   nd = malloc(sizeof(*nd)+len+INITPTR*_MAX_PATH);

		   if (!nd) {
			  return -1;
		   }

		   nd->alloc = len+INITPTR*_MAX_PATH;
		   nd->used = 0;
		   nd->N = ca->chars;
		   ca->chars = nd;
		}
	 }


	ca->array[ca->count].strlength = len;
	ca->array[ca->count].strptr = ca->chars->data+ca->chars->used;
	memcpy(ca->array[ca->count++].strptr, str, len);
	ca->chars->used += len+1;
	ca->chars->data[ca->chars->used] = 0;

	return 0;
}

There are no comments on this page. [Add comment]

Valid XHTML 1.0 Transitional :: Valid CSS :: Powered by Wikka Wakka Wiki 1.1.6.7
Page was generated in 0.3265 seconds