CmsRet oal_Net_getGMACPortIfNameList(char **GMACPortIfNameList) { #ifdef CMS_BRCM_GMAC #ifdef DESKTOP_LINUX *GMACPortIfNameList = cmsMem_alloc(512, 0); strcpy(*GMACPortIfNameList, "eth1,eth3"); #else SINT32 skfd; struct ifreq ifr; if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { cmsLog_error("Error openning socket for getting the GMAC enet port list"); return CMSRET_INTERNAL_ERROR; } /* Get the name -> if_index mapping for ethswctl */ strcpy(ifr.ifr_name, "bcmsw"); if (ioctl(skfd, SIOCGIFINDEX, &ifr) < 0) { close(skfd); cmsLog_debug("bcmsw interface does not exist. Error: %d", errno); return CMSRET_INTERNAL_ERROR; } /* Allocate dynamic memory to hold max interface names (eth0,eth1,..eth10<cr>)*/ if ((*GMACPortIfNameList = cmsMem_alloc(((MAX_GMAC_ETH_PORT * (IFNAMSIZ+1)) + 2), ALLOC_ZEROIZE)) == NULL) { cmsLog_error("Fail to alloc mem in getting the GMAC enet port list"); close(skfd); return CMSRET_RESOURCE_EXCEEDED; } memset((void *) &ifr, sizeof(ifr), 0); ifr.ifr_data = *GMACPortIfNameList; if (ioctl(skfd, SIOCGGMACPORT, &ifr) < 0) { cmsLog_error("ioct error in getting the GMAC enet port list. Error: %d", errno); close(skfd); CMSMEM_FREE_BUF_AND_NULL_PTR(*GMACPortIfNameList); return CMSRET_INTERNAL_ERROR; } close(skfd); cmsLog_debug("GMACPortIfNameList=%s, strlen=%d", *GMACPortIfNameList, strlen(*GMACPortIfNameList)); #endif /* DESKTOP_LINUX */ #endif /* CMS_BRCM_GMAC */ return CMSRET_SUCCESS; }
void *cmsMem_realloc(void *origBuf, UINT32 size) { void *buf; UINT32 origSize, origAllocSize, origAllocFlags; UINT32 allocSize; UINT32 *intBuf; if (origBuf == NULL) { cmsLog_error("cannot take a NULL buffer"); return NULL; } if (size == 0) { cmsMem_free(origBuf); return NULL; } allocSize = REAL_ALLOC_SIZE(size); intBuf = (UINT32 *) (((UINT32) origBuf) - CMS_MEM_HEADER_LENGTH); origAllocFlags = intBuf[0]; origSize = intBuf[1]; /* sanity check the original length */ if (intBuf[1] != (intBuf[2] ^ 0xffffffff)) { cmsLog_error("memory underflow detected, %d %d", intBuf[1], intBuf[2]); cmsAst_assert(0); return NULL; } origAllocSize = REAL_ALLOC_SIZE(origSize); if (allocSize <= origAllocSize) { /* currently, I don't shrink buffers, but could in the future. */ return origBuf; } buf = cmsMem_alloc(allocSize, origAllocFlags); if (buf != NULL) { /* got new buffer, copy orig buffer to new buffer */ memcpy(buf, origBuf, origSize); cmsMem_free(origBuf); } else { /* * We could not allocate a bigger buffer. * Return NULL but leave the original buffer untouched. */ } return buf; }
CmsRet cmsPsp_set(const char *key, const void *buf, UINT32 bufLen) { char *currBuf; SINT32 count; if ((currBuf = cmsMem_alloc(bufLen, 0)) == NULL) { return CMSRET_RESOURCE_EXCEEDED; } /* * Writing to the scratch pad is a non-preemptive time consuming * operation that should be avoided. * Check if the new data is the same as the old data. */ count = devCtl_boardIoctl(BOARD_IOCTL_FLASH_READ, SCRATCH_PAD, (char *) key, 0, (SINT32) bufLen, currBuf); if (count == (SINT32) bufLen) { if (memcmp(currBuf, buf, bufLen) == 0) { cmsMem_free(currBuf); /* set is exactly the same as the orig data, no set needed */ return CMSRET_SUCCESS; } cmsMem_free(currBuf); } return (devCtl_boardIoctl(BOARD_IOCTL_FLASH_WRITE, SCRATCH_PAD, (char *) key, 0, (SINT32) bufLen, (void *) buf)); }
CmsRet cmsEid_getStringNamesFromBitMask(UINT16 bitMask, char **buf) { UINT32 i, mask; UINT32 len=1; /* for empty mask, return a buffer with an empty string. */ UINT32 idx=0; UINT32 numBits = sizeof(bitMask) * 8; const CmsEntityInfo *info; UBOOL8 firstName=TRUE; CmsRet ret = CMSRET_SUCCESS; /* first loop calculates how much space needed for string names */ for (mask=1, i=0; i < numBits; i++) { info = cmsEid_getEntityInfoByAccessBit(bitMask & mask); if (info == NULL) { if (bitMask & mask) { cmsLog_error("unrecognized bitmask 0x%x", (bitMask & mask)); ret = CMSRET_SUCCESS_UNRECOGNIZED_DATA_IGNORED; } } else { len += strlen(info->name) + 1; } mask = mask << 1; } if (((*buf) = cmsMem_alloc(len, ALLOC_ZEROIZE)) == NULL) { return CMSRET_RESOURCE_EXCEEDED; } /* this loop copies string names into buffer */ for (mask=1, i=0; i < numBits; i++) { info = cmsEid_getEntityInfoByAccessBit(bitMask & mask); if (info != NULL) { if (firstName) { idx = sprintf((*buf), "%s", info->name); firstName = FALSE; } else { idx += sprintf(&((*buf)[idx]), ",%s", info->name); } } mask = mask << 1; } cmsAst_assert(idx < len); return ret; }
CmsRet cmsUtl_parsePrefixAddress(const char *prefixAddr, char *address, UINT32 *plen) { CmsRet ret = CMSRET_SUCCESS; char *tmpBuf; char *separator; UINT32 len; if (prefixAddr == NULL || address == NULL || plen == NULL) { return CMSRET_INVALID_ARGUMENTS; } cmsLog_debug("prefixAddr=%s", prefixAddr); *address = '\0'; *plen = 128; len = strlen(prefixAddr); if ((tmpBuf = cmsMem_alloc(len+1, 0)) == NULL) { cmsLog_error("alloc of %d bytes failed", len); ret = CMSRET_INTERNAL_ERROR; } else { sprintf(tmpBuf, "%s", prefixAddr); separator = strchr(tmpBuf, '/'); if (separator != NULL) { /* break the string into two strings */ *separator = 0; separator++; while ((isspace(*separator)) && (*separator != 0)) { /* skip white space after comma */ separator++; } *plen = atoi(separator); cmsLog_debug("plen=%d", *plen); } cmsLog_debug("address=%s", tmpBuf); if (strlen(tmpBuf) < BUFLEN_40 && *plen <= 128) { strcpy(address, tmpBuf); } else { ret = CMSRET_INVALID_ARGUMENTS; } cmsMem_free(tmpBuf); } return ret; } /* End of cmsUtl_parsePrefixAddress() */
/* Get the existing interface names in the kernel, regardless they're active * or not. If success, the ifNameList will be assigned a new allocated string * containing names separated by commas. It may look like * "lo,dsl0,eth0,eth1,usb0,wl0". * * Caller should free ifNameList by cmsMem_free() after use. * * Return CMSRET_SUCCESS if success, error code otherwise. */ CmsRet oalNet_getIfNameList(char **ifNameList) { #ifdef DESKTOP_LINUX *ifNameList = cmsMem_alloc(512, 0); sprintf(*ifNameList, "lo,dsl0,eth0,eth1,usb0,moca0,moca1"); #else struct if_nameindex *ni_list = if_nameindex(); struct if_nameindex *ni_list2 = ni_list; char buf[1024]; char *pbuf = buf; int len; if (ni_list == NULL) return CMSRET_INTERNAL_ERROR; /* Iterate through the array of interfaces to concatenate interface * names, separated by commas */ while(ni_list->if_index) { len = strlen(ni_list->if_name); memcpy(pbuf, ni_list->if_name, len); pbuf += len; *pbuf++ = ','; ni_list++; } len = pbuf - buf; buf[len-1] = 0; if_freenameindex(ni_list2); /* Allocate dynamic memory for interface name list */ if ((*ifNameList = cmsMem_alloc(len, 0)) == NULL) return CMSRET_RESOURCE_EXCEEDED; memcpy(*ifNameList, buf, len); #endif /* DESKTOP_LINUX */ return CMSRET_SUCCESS; }
CmsRet cmsUtl_macStrToNum(const char *macStr, UINT8 *macNum) { char *pToken = NULL; char *pLast = NULL; char *buf; SINT32 i; if (macNum == NULL || macStr == NULL) { cmsLog_error("Invalid macNum/macStr %p/%p", macNum, macStr); return CMSRET_INVALID_ARGUMENTS; } if (cmsUtl_isValidMacAddress(macStr) == FALSE) { return CMSRET_INVALID_PARAM_VALUE; } if ((buf = (char *) cmsMem_alloc(MAC_STR_LEN+1, ALLOC_ZEROIZE)) == NULL) { cmsLog_error("alloc of %d bytes failed", MAC_STR_LEN+1); return CMSRET_RESOURCE_EXCEEDED; } /* need to copy since strtok_r updates string */ strcpy(buf, macStr); /* Mac address has the following format * xx:xx:xx:xx:xx:xx where x is hex number */ pToken = strtok_r(buf, ":", &pLast); macNum[0] = (UINT8) strtol(pToken, (char **)NULL, 16); for (i = 1; i < MAC_ADDR_LEN; i++) { pToken = strtok_r(NULL, ":", &pLast); macNum[i] = (UINT8) strtol(pToken, (char **)NULL, 16); } cmsMem_free(buf); return CMSRET_SUCCESS; }
char *cmsUtl_getDhcpVendorIdsFromAggregateString(const char *aggregateString) { char *vendorIds, *vendorId, *ptr, *savePtr=NULL; char *copy; UINT32 count=0; if (aggregateString == NULL) { return NULL; } vendorIds = cmsMem_alloc(MAX_PORTMAPPING_DHCP_VENDOR_IDS * (DHCP_VENDOR_ID_LEN + 1), ALLOC_ZEROIZE); if (vendorIds == NULL) { cmsLog_error("allocation of vendorIds buffer failed"); return NULL; } copy = cmsMem_strdup(aggregateString); ptr = strtok_r(copy, ",", &savePtr); while ((ptr != NULL) && (count < MAX_PORTMAPPING_DHCP_VENDOR_IDS)) { vendorId = &(vendorIds[count * (DHCP_VENDOR_ID_LEN + 1)]); /* * copy at most DHCP_VENDOR_ID_LEN bytes. Since each chunk in the linear * buffer is DHCP_VENDOR_ID_LEN+1 bytes long and initialized to 0, * we are guaranteed that each vendor id is null terminated. */ strncpy(vendorId, ptr, DHCP_VENDOR_ID_LEN); count++; ptr = strtok_r(NULL, ",", &savePtr); } cmsMem_free(copy); return vendorIds; }
char *cmsUtl_getAggregateStringFromDhcpVendorIds(const char *vendorIds) { char *aggregateString; const char *vendorId; UINT32 i, count=0; if (vendorIds == NULL) { return NULL; } aggregateString = cmsMem_alloc(MAX_PORTMAPPING_DHCP_VENDOR_IDS * (DHCP_VENDOR_ID_LEN + 1), ALLOC_ZEROIZE); if (aggregateString == NULL) { cmsLog_error("allocation of aggregate string failed"); return NULL; } for (i=0; i < MAX_PORTMAPPING_DHCP_VENDOR_IDS; i++) { vendorId = &(vendorIds[i * (DHCP_VENDOR_ID_LEN + 1)]); if (*vendorId != '\0') { if (count > 0) { strcat(aggregateString, ","); } /* strncat writes at most DHCP_VENDOR_ID_LEN+1 bytes, which includes the trailing NULL */ strncat(aggregateString, vendorId, DHCP_VENDOR_ID_LEN); count++; } } return aggregateString; }
/** Return a pointer to the beginning of the requested flash buffer. * * On DESKTOP_LINUX, this just opens the fake flash file, allocates a buffer, * read contents of fake flash file into buffer, and returns pointer to the * buffer. Persistent flash data is the only thing in the flash file (for now). * If fake flash file is not present, create one and fill it with zeros. */ char *fake_getSharedBlks(int start_block, int num_blocks) { UINT32 bufLen; char *buf=NULL; char path[BUFLEN_1024]; struct stat statbuf; int rc, fd; CmsRet ret; cmsLog_debug("reading block %d through %d", start_block, start_block+num_blocks); if (start_block != 0) { cmsLog_error("cannot handle non-zero start block yet."); return NULL; } if (num_blocks > FAKE_NUM_PSP_FLASH_BLOCKS) { cmsLog_error("requested more blocks than PSP flash blocks, not handled."); return NULL; } /* first allocate the buffer we will need for the read */ bufLen = FAKE_FLASH_BLOCK_SIZE * FAKE_NUM_PSP_FLASH_BLOCKS; if ((buf = cmsMem_alloc(bufLen, ALLOC_ZEROIZE)) == NULL) { cmsLog_error("malloc of %d bytes failed", bufLen); return NULL; } /* form path to the flash file */ if ((ret = cmsUtl_getBaseDir(path, sizeof(path))) != CMSRET_SUCCESS) { cmsLog_error("getBaseDir failed, abort func"); cmsMem_free(buf); return NULL; } else { UINT32 offset; offset = strlen(path); snprintf(&(path[offset]), sizeof(path)-offset, "/%s", FAKE_FLASH_PSP_FILENAME); } cmsLog_debug("checking for flash file at %s", path); if ((rc = stat(path, &statbuf)) < 0) { cmsLog_debug("creating fake flash file and initialize to zeros"); fd = open(path, O_CREAT|O_RDWR, 0644); if (fd < 0) { cmsLog_error("create of flash file %s failed, errno=%d", path, errno); cmsMem_free(buf); return NULL; } /* fill rest of file with zeros */ rc = write(fd, buf, bufLen); cmsLog_debug("filler write returned %d", rc); close(fd); } /* * at this point, we know there is a flash file, so just open it and read it. * Don't bother with offsets for now. Just assume PSP is at the beginning * of the flash. */ fd = open(path, O_RDWR); rc = read(fd, buf, num_blocks * FAKE_FLASH_BLOCK_SIZE); if (rc != num_blocks * FAKE_FLASH_BLOCK_SIZE) { cmsLog_error("unexpected rc %d from read, expected %d", rc, num_blocks * FAKE_FLASH_BLOCK_SIZE); CMSMEM_FREE_BUF_AND_NULL_PTR(buf); } close(fd); return buf; }
CmsRet cmsUtl_parseDNS(const char *inDsnServers, char *outDnsPrimary, char *outDnsSecondary) { CmsRet ret = CMSRET_SUCCESS; char *tmpBuf; char *separator; UINT32 len; if (inDsnServers == NULL) { return CMSRET_INVALID_ARGUMENTS; } cmsLog_debug("entered: DDNSservers=>%s<=", inDsnServers); if (outDnsPrimary) { strcpy(outDnsPrimary, "0.0.0.0"); } if (outDnsSecondary) { strcpy(outDnsSecondary, "0.0.0.0"); } len = strlen(inDsnServers); if ((tmpBuf = cmsMem_alloc(len+1, 0)) == NULL) { cmsLog_error("alloc of %d bytes failed", len); ret = CMSRET_INTERNAL_ERROR; } else { sprintf(tmpBuf, "%s", inDsnServers); separator = strstr(tmpBuf, ","); if (separator != NULL) { /* break the string into two strings */ *separator = 0; separator++; while ((isspace(*separator)) && (*separator != 0)) { /* skip white space after comma */ separator++; } if (outDnsSecondary != NULL) { if (cmsUtl_isValidIpv4Address(separator)) { strcpy(outDnsSecondary, separator); } cmsLog_debug("dnsSecondary=%s", outDnsSecondary); } } if (outDnsPrimary != NULL) { if (cmsUtl_isValidIpv4Address(tmpBuf)) { strcpy(outDnsPrimary, tmpBuf); } cmsLog_debug("dnsPrimary=%s", outDnsPrimary); } cmsMem_free(tmpBuf); } return ret; }
CmsRet oalMsg_init(CmsEntityId eid, void **msgHandle) { CmsMsgHandle *handle; const CmsEntityInfo *eInfo; struct sockaddr_un serverAddr; SINT32 rc; if ((eInfo = cmsEid_getEntityInfo(eid)) == NULL) { cmsLog_error("Invalid eid %d", eid); return CMSRET_INVALID_ARGUMENTS; } if ((handle = (CmsMsgHandle *) cmsMem_alloc(sizeof(CmsMsgHandle), ALLOC_ZEROIZE)) == NULL) { cmsLog_error("could not allocate storage for msg handle"); return CMSRET_RESOURCE_EXCEEDED; } /* store caller's eid */ handle->eid = eid; #ifdef DESKTOP_LINUX /* * Applications may be run without smd on desktop linux, so if we * don't see a socket for smd, don't bother connecting to it. */ { struct stat statbuf; if ((rc = stat(SMD_MESSAGE_ADDR, &statbuf)) < 0) { handle->commFd = CMS_INVALID_FD; handle->standalone = TRUE; *msgHandle = (void *) handle; cmsLog_notice("no smd server socket detected, running in standalone mode."); return CMSRET_SUCCESS; } } #endif /* DESKTOP_LINUX */ /* * Create a unix domain socket. */ handle->commFd = socket(AF_LOCAL, SOCK_STREAM, 0); if (handle->commFd < 0) { cmsLog_error("Could not create socket"); cmsMem_free(handle); return CMSRET_INTERNAL_ERROR; } /* * Set close-on-exec, even though all apps should close their * fd's before fork and exec. */ if ((rc = fcntl(handle->commFd, F_SETFD, FD_CLOEXEC)) != 0) { cmsLog_error("set close-on-exec failed, rc=%d errno=%d", rc, errno); close(handle->commFd); cmsMem_free(handle); return CMSRET_INTERNAL_ERROR; } /* * Connect to smd. */ memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sun_family = AF_LOCAL; strncpy(serverAddr.sun_path, SMD_MESSAGE_ADDR, sizeof(serverAddr.sun_path)); rc = connect(handle->commFd, (struct sockaddr *) &serverAddr, sizeof(serverAddr)); if (rc != 0) { cmsLog_error("connect to %s failed, rc=%d errno=%d", SMD_MESSAGE_ADDR, rc, errno); close(handle->commFd); cmsMem_free(handle); return CMSRET_INTERNAL_ERROR; } else { cmsLog_debug("commFd=%d connected to smd", handle->commFd); } /* send a launched message to smd */ { CmsRet ret; CmsMsgHeader launchMsg = EMPTY_MSG_HEADER; launchMsg.type = CMS_MSG_APP_LAUNCHED; launchMsg.src = (eInfo->flags & EIF_MULTIPLE_INSTANCES) ? MAKE_SPECIFIC_EID(getpid(), eid) : eid; launchMsg.dst = EID_SMD; launchMsg.flags_event = 1; if ((ret = oalMsg_send(handle->commFd, &launchMsg)) != CMSRET_SUCCESS) { close(handle->commFd); cmsMem_free(handle); return CMSRET_INTERNAL_ERROR; } else { cmsLog_debug("sent LAUNCHED message to smd"); } } /* successful, set handle pointer */ *msgHandle = (void *) handle; return CMSRET_SUCCESS; }
CmsRet oalMsg_receive(SINT32 fd, CmsMsgHeader **buf, UINT32 *timeout) { CmsMsgHeader *msg; SINT32 rc; CmsRet ret; if (buf == NULL) { cmsLog_error("buf is NULL!"); return CMSRET_INVALID_ARGUMENTS; } else { *buf = NULL; } if (timeout) { if ((ret = waitForDataAvailable(fd, *timeout)) != CMSRET_SUCCESS) { return ret; } } /* * Read just the header in the first read. * Do not try to read more because we might get part of * another message in the TCP socket. */ msg = (CmsMsgHeader *) cmsMem_alloc(sizeof(CmsMsgHeader), ALLOC_ZEROIZE); if (msg == NULL) { cmsLog_error("alloc of msg header failed"); return CMSRET_RESOURCE_EXCEEDED; } rc = read(fd, msg, sizeof(CmsMsgHeader)); if ((rc == 0) || ((rc == -1) && (errno == 131))) /* new 2.6.21 kernel seems to give us this before rc==0 */ { /* broken connection */ cmsMem_free(msg); return CMSRET_DISCONNECTED; } else if (rc < 0 || rc != sizeof(CmsMsgHeader)) { cmsLog_error("bad read, rc=%d errno=%d", rc, errno); cmsMem_free(msg); return CMSRET_INTERNAL_ERROR; } if (msg->dataLength > 0) { SINT32 totalReadSoFar=0; SINT32 totalRemaining=msg->dataLength; char *inBuf; /* there is additional data in the message */ msg = (CmsMsgHeader *) cmsMem_realloc(msg, sizeof(CmsMsgHeader) + msg->dataLength); if (msg == NULL) { cmsLog_error("realloc to %d bytes failed", sizeof(CmsMsgHeader) + msg->dataLength); cmsMem_free(msg); return CMSRET_RESOURCE_EXCEEDED; } inBuf = (char *) (msg + 1); while (totalReadSoFar < msg->dataLength) { cmsLog_debug("reading segment: soFar=%d total=%d", totalReadSoFar, totalRemaining); if (timeout) { if ((ret = waitForDataAvailable(fd, *timeout)) != CMSRET_SUCCESS) { cmsMem_free(msg); return ret; } } rc = read(fd, inBuf, totalRemaining); if (rc <= 0) { cmsLog_error("bad data read, rc=%d errno=%d readSoFar=%d remaining=%d", rc, errno, totalReadSoFar, totalRemaining); cmsMem_free(msg); return CMSRET_INTERNAL_ERROR; } else { inBuf += rc; totalReadSoFar += rc; totalRemaining -= rc; } } } *buf = msg; return CMSRET_SUCCESS; }
/** Give a single string, allocate and fill in an array of char *'s * each pointing to an individually malloc'd buffer containing a single * argument in the string; the array will end with a char * slot containing NULL. * * This array can be passed to execv. * This array must be freed by calling freeArgs. */ CmsRet parseArgs(const char *cmd, const char *args, char ***argv) { UINT32 numArgs=3, i, len, argIndex=0; UBOOL8 inSpace=TRUE; const char *cmdStr; char **array; len = (args == NULL) ? 0 : strlen(args); /* * First count the number of spaces to determine the number of args * there are in the string. */ for (i=0; i < len; i++) { if ((args[i] == ' ') && (!inSpace)) { numArgs++; inSpace = TRUE; } else { inSpace = FALSE; } } array = (char **) cmsMem_alloc((numArgs) * sizeof(char *), ALLOC_ZEROIZE); if (array == NULL) { return CMSRET_RESOURCE_EXCEEDED; } /* locate the command name, last part of string */ cmdStr = strrchr(cmd, '/'); if (cmdStr == NULL) { cmdStr = cmd; } else { cmdStr++; /* move past the / */ } /* copy the command into argv[0] */ array[argIndex] = cmsMem_alloc(strlen(cmdStr) + 1, ALLOC_ZEROIZE); if (array[argIndex] == NULL) { cmsLog_error("malloc of %d failed", strlen(cmdStr) + 1); freeArgs(array); return CMSRET_RESOURCE_EXCEEDED; } else { strcpy(array[argIndex], cmdStr); argIndex++; } /* * Wow, this is going to be incredibly messy. I have to malloc a buffer * for each arg and copy them in individually. */ inSpace = TRUE; for (i=0; i < len; i++) { if ((args[i] == ' ') && (!inSpace)) { numArgs++; inSpace = TRUE; } else if ((args[i] != ' ') && (inSpace)) { UINT32 startIndex, endIndex; /* * this is the first character I've seen after a space. * Figure out how many letters this arg is, malloc a buffer * to hold it, and copy it into the buffer. */ startIndex = i; endIndex = i; while ((endIndex < len) && (args[endIndex] != ' ')) { endIndex++; } array[argIndex] = cmsMem_alloc(endIndex - startIndex + 1, ALLOC_ZEROIZE); if (array[argIndex] == NULL) { cmsLog_error("malloc of %d failed", endIndex - startIndex + 1); freeArgs(array); return CMSRET_RESOURCE_EXCEEDED; } memcpy(array[argIndex], &args[startIndex], endIndex - startIndex); /* cmsLog_debug("index=%d len=%d (%s)", argIndex, endIndex - startIndex, &args[startIndex]); */ argIndex++; inSpace = FALSE; } } /* check what we did */ i = 0; while (array[i] != NULL) { cmsLog_debug("argv[%d] = %s", i, array[i]); i++; } (*argv) = array; return CMSRET_SUCCESS; }