This is ImprovConnector.m in view mode; [Download] [Up]
// ImprovConnector.m // By Judy D. Halchin, Educational Computing Services, Allegheny College. // Copyright 1993 Allegheny College. // You may freely copy, distribute and reuse this code. // Allegheny College and the author disclaim any warranty of any kind, // expressed or implied, as to its fitness for any particular use. // This work was partially supported by a Teacher Preparation grant from the // National Science Foundation. #import "ImprovConnector.h" #import "imxPublicAPI.h" @implementation ImprovConnector enum errorMessages { IC_GETSELECTION = NX_APPBASE, IC_GETINFO, IC_GETCELLVALUE, IC_SELECTIONTYPE, IC_GETRANGE, IC_SETSELECTION, IC_ADDITEMS, IC_RENAME, IC_SETCELLVALUE, IC_UPDATE, IC_NUMBERCOLUMNS, IC_NEWSHEET, IC_BADPARAMETERS, IC_GETROWS, IC_GETCOLUMNS, IC_GETCATEGORIES, IC_NUMBERCATEGORIES, IC_BADCATEGORIES, IC_GETITEMINFO, IC_GETRANGEINFO, IC_COLUMNCHECK, IC_CELLTYPE, IC_ADDCOLUMNS }; enum handlingValues { IC_USEVALUE = 0, IC_USEZERO, IC_SKIPVALUE, IC_CONVERT, IC_ERROR }; - init { [super init]; NXWriteDefault("Improv", "enableOakumPort", "Yes"); sheet = (char *)malloc(1); model = (char *)malloc(1); strcpy(sheet, ""); strcpy(model, ""); emptyCellHandling = WB_ZERO; textCellHandling = WB_ERROR; return self; } - setCellHandlingForEmpty:(int)handlingForEmpty text:(int)handlingForText { emptyCellHandling = handlingForEmpty; textCellHandling = handlingForText; return self; } - (int)doubleData:(double **)data fromColumn:(char *)columnName dataCount:(int *)numRows { return [self dataType:WB_DOUBLEDATA double:data float:NULL int:NULL string:NULL fromColumn:columnName dataCount:numRows]; } - (int)floatData:(float **)data fromColumn:(char *)columnName dataCount:(int *)numRows { return [self dataType:WB_FLOATDATA double:NULL float:data int:NULL string:NULL fromColumn:columnName dataCount:numRows]; } - (int)intData:(int **)data fromColumn:(char *)columnName dataCount:(int *)numRows { return [self dataType:WB_INTDATA double:NULL float:NULL int:data string:NULL fromColumn:columnName dataCount:numRows]; } - (int)stringData:(char ***)data fromColumn:(char *)columnName dataCount:(int *)numRows { return [self dataType:WB_STRINGDATA double:NULL float:NULL int:NULL string:data fromColumn:columnName dataCount:numRows]; } - (int)dataType:(int)dataType double:(double **)doubleData float:(float **)floatData int:(int **)intData string:(char ***)stringData fromColumn:(char *)columnName dataCount:(int *)numRows { char *selName, *viewName, *sheetName, *modelName, *lastRow, *firstRow; char *parent, **rowNames, cellName[100], *cellString, *parentName; char **categoryNames, *categoryList; imxSelType selType; imxCellType cellType; int imxReturnCode, myReturnCode=0, rowCount, rowIndex, categoryCount; int dataIndex; double cellValue; BOOL found; NX_DURING // make sure the named column really exists and get its category // get the current sheet and model if ((imxReturnCode = imxGetSelection(&selName, &selType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); strcpy(sheet, sheetName); strcpy(model, modelName); // make sure we can find the given column and that it is a column if ((imxReturnCode = imxGetItemInfo(&parentName, &firstRow, &lastRow, columnName, sheet, model)) != 0) NX_RAISE(IC_GETINFO, &imxReturnCode, NULL); if (parentName == NULL) NX_RAISE(IC_COLUMNCHECK, &imxReturnCode, NULL); parent = (char *)malloc(strlen(parentName) + 1); strcpy(parent, parentName); if ((imxReturnCode = imxGetCategoryList(&categoryList, sheet, model)) != 0) NX_RAISE(IC_GETCATEGORIES, &imxReturnCode, NULL); [self getNames:&categoryNames fromList:categoryList count:&categoryCount]; for (rowIndex = 0, found = NO; (rowIndex < categoryCount) && !found; rowIndex++) if (strcmp(categoryNames[rowIndex], parent) == 0) found = YES; [self freeData:categoryNames count:categoryCount]; if (!found) { free(parent); NX_RAISE(IC_COLUMNCHECK, NULL, NULL); } // get the list of row names if ((myReturnCode = [self getRows:&rowNames rowCount:&rowCount forColumnCategory:parent]) != 0) NX_RAISE(IC_GETROWS, NULL, NULL); free(parent); // get the data from the column switch (dataType) { case WB_DOUBLEDATA: *doubleData = (double *)malloc(rowCount * sizeof(double)); break; case WB_FLOATDATA: *floatData = (float *)malloc(rowCount * sizeof(float)); break; case WB_INTDATA: *intData = (int *)malloc(rowCount * sizeof(int)); break; case WB_STRINGDATA: *stringData = (char **)malloc(rowCount * sizeof(char *)); break; } for (rowIndex = 0, dataIndex = 0; rowIndex < rowCount; rowIndex++) { sprintf(cellName, "%s:%s", columnName, rowNames[rowIndex]); if ((imxReturnCode = imxGetCellValue(cellName, &cellType, &cellValue, &cellString, sheet, model)) != 0) NX_RAISE(IC_GETCELLVALUE, &imxReturnCode, &dataType); switch ([self handleCell:cellType forData:dataType]) { case IC_SKIPVALUE: dataIndex--; break; case IC_USEVALUE: switch (dataType) { case WB_DOUBLEDATA: (*doubleData)[dataIndex] = cellValue; break; case WB_FLOATDATA: (*floatData)[dataIndex] = cellValue; break; case WB_INTDATA: (*intData)[dataIndex] = cellValue; break; case WB_STRINGDATA: (*stringData)[dataIndex] = (char *)malloc (strlen(cellString) + 1); strcpy((*stringData)[dataIndex], cellString); break; } break; case IC_USEZERO: switch (dataType) { case WB_DOUBLEDATA: (*doubleData)[dataIndex] = 0; break; case WB_FLOATDATA: (*floatData)[dataIndex] = 0; break; case WB_INTDATA: (*intData)[dataIndex] = 0; break; case WB_STRINGDATA: (*stringData)[dataIndex] = (char *)malloc(1); strcpy((*stringData)[dataIndex], ""); break; } break; case IC_CONVERT: // data type must be string to get this case (*stringData)[dataIndex] = (char *)malloc(15); sprintf((*stringData)[dataIndex], "%f", cellValue); [self deleteTrailingZeros:(*stringData)[dataIndex]]; break; case IC_ERROR: NX_RAISE(IC_CELLTYPE, NULL, NULL); break; } dataIndex++; } // send back the number of rows *numRows = dataIndex; // free stuff [self freeData:rowNames count:rowCount]; NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: if (*(int *)NXLocalHandler.data1 == imxerr_NO_SELECTION) myReturnCode = WB_NOTHINGSELECTED; else myReturnCode = WB_UNKNOWNERROR; break; case IC_GETINFO: if (*(int *)NXLocalHandler.data1 == imxerr_ITEM_NOT_FOUND) myReturnCode = WB_NOSUCHCOLUMN; else myReturnCode = WB_UNKNOWNERROR; break; case IC_GETCATEGORIES: free(parent); myReturnCode = WB_UNKNOWNERROR; break; case IC_GETROWS: free(parent); break; case IC_COLUMNCHECK: myReturnCode = WB_NOSUCHCOLUMN; break; case IC_GETCELLVALUE: switch (dataType) { case WB_DOUBLEDATA: free(*doubleData); break; case WB_FLOATDATA: free(*floatData); break; case WB_INTDATA: free(*intData); break; case WB_STRINGDATA: [self freeData:*stringData count:dataIndex]; break; } [self freeData:rowNames count:rowCount]; myReturnCode = WB_UNKNOWNERROR; break; case IC_CELLTYPE: switch (dataType) { case WB_DOUBLEDATA: free(*doubleData); break; case WB_FLOATDATA: free(*floatData); break; case WB_INTDATA: free(*intData); break; case WB_STRINGDATA: [self freeData:*stringData count:dataIndex]; break; } [self freeData:rowNames count:rowCount]; myReturnCode = WB_WRONGCELLTYPE; break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)doubleData:(double ***)data fromSelectedColumnsCount:(int *)numColumns byRows:(BOOL)byRows dataCount:(int *)numRows { return [self dataType:WB_DOUBLEDATA double:data float:NULL int:NULL string:NULL fromSelectedColumnsCount:numColumns byRows:byRows dataCount:numRows]; } - (int)floatData:(float ***)data fromSelectedColumnsCount:(int *)numColumns byRows:(BOOL)byRows dataCount:(int *)numRows { return [self dataType:WB_FLOATDATA double:NULL float:data int:NULL string:NULL fromSelectedColumnsCount:numColumns byRows:byRows dataCount:numRows]; } - (int)intData:(int ***)data fromSelectedColumnsCount:(int *)numColumns byRows:(BOOL)byRows dataCount:(int *)numRows { return [self dataType:WB_INTDATA double:NULL float:NULL int:data string:NULL fromSelectedColumnsCount:numColumns byRows:byRows dataCount:numRows]; } - (int)stringData:(char ****)data fromSelectedColumnsCount:(int *)numColumns byRows:(BOOL)byRows dataCount:(int *)numRows { return [self dataType:WB_STRINGDATA double:NULL float:NULL int:NULL string:data fromSelectedColumnsCount:numColumns byRows:byRows dataCount:numRows]; } - (int)dataType:(int)dataType double:(double ***)doubleData float:(float ***)floatData int:(int ***)intData string:(char ****)stringData fromSelectedColumnsCount:(int *)numColumns byRows:(BOOL)byRows dataCount:(int *)numRows { char *selectionName, *viewName, *sheetName, *modelName, cellName[100]; char *parent, *selection, *cellString; int itemCount, itemIndex, rowCount, rowIndex; int firstIndex, secondIndex, firstCount, secondCount; int imxReturnCode, myReturnCode = 0, dataIndex; imxSelType selectionType; imxCellType cellType; char *itemList, *selectedCategory, **itemNames, **rowNames; double cellValue; NX_DURING // find out what sort of thing is currently selected, should be item(s) if ((imxReturnCode = imxGetSelection(&selectionName, &selectionType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); if (selectionType != imxsel_ITEM) NX_RAISE(IC_SELECTIONTYPE, NULL, NULL); selection = (char *)malloc(strlen(selectionName) + 1); strcpy(selection, selectionName); strcpy(sheet, ""); strcpy(model, ""); // separate names of selected items and count them if ((imxReturnCode = imxGetItemRangeInfo(&parent, &itemList, selection, sheet, model)) != 0) NX_RAISE(IC_GETRANGE, &imxReturnCode, NULL); free(selection); selectedCategory = (char *)malloc(strlen(parent) + 1); strcpy(selectedCategory, parent); [self getNames:&itemNames fromList:itemList count:&itemCount]; // get the list of row names if ((myReturnCode = [self getRows:&rowNames rowCount:&rowCount forColumnCategory:selectedCategory]) != 0) NX_RAISE(IC_GETROWS, NULL, NULL); free(selectedCategory); // get the data from the cells and store it in an array if (byRows) { firstCount = rowCount; secondCount = itemCount; } else { firstCount = itemCount; secondCount = rowCount; } switch (dataType) { case WB_DOUBLEDATA: *doubleData = (double **)malloc(firstCount * sizeof(double *)); break; case WB_FLOATDATA: *floatData = (float **)malloc(firstCount * sizeof(float *)); break; case WB_INTDATA: *intData = (int **)malloc(firstCount * sizeof(int *)); break; case WB_STRINGDATA: *stringData = (char ***)malloc(firstCount * sizeof(char **)); break; } for (firstIndex = 0,dataIndex=0; firstIndex < firstCount; firstIndex++) { switch (dataType) { case WB_DOUBLEDATA: (*doubleData)[dataIndex] = (double *)malloc (secondCount * sizeof(double)); break; case WB_FLOATDATA: (*floatData)[dataIndex] = (float *)malloc (secondCount * sizeof(float)); break; case WB_INTDATA: (*intData)[dataIndex] = (int *)malloc (secondCount * sizeof(int)); break; case WB_STRINGDATA: (*stringData)[dataIndex] = (char **)malloc (secondCount * sizeof(char *)); break; } for (secondIndex = 0; secondIndex < secondCount; secondIndex++) { if (byRows) { rowIndex = firstIndex; itemIndex = secondIndex; } else { rowIndex = secondIndex; itemIndex = firstIndex; } sprintf(cellName, "%s:%s", itemNames[itemIndex], rowNames[rowIndex]); if ((imxReturnCode = imxGetCellValue(cellName, &cellType, &cellValue, &cellString, sheet, model)) != 0) NX_RAISE(IC_GETCELLVALUE, NULL, NULL); switch ([self handleCell:cellType forData:dataType]) { case IC_SKIPVALUE: dataIndex--; secondIndex = secondCount; break; case IC_USEVALUE: switch (dataType) { case WB_DOUBLEDATA: (*doubleData)[dataIndex][secondIndex] = cellValue; break; case WB_FLOATDATA: (*floatData)[dataIndex][secondIndex] = cellValue; break; case WB_INTDATA: (*intData)[dataIndex][secondIndex] = cellValue; break; case WB_STRINGDATA: (*stringData)[dataIndex][secondIndex] = (char *)malloc(strlen(cellString) + 1); strcpy((*stringData)[dataIndex][secondIndex], cellString); break; } break; case IC_USEZERO: switch (dataType) { case WB_DOUBLEDATA: (*doubleData)[dataIndex][secondIndex] = 0; break; case WB_FLOATDATA: (*floatData)[dataIndex][secondIndex] = 0; break; case WB_INTDATA: (*intData)[dataIndex][secondIndex] = 0; break; case WB_STRINGDATA: (*stringData)[dataIndex][secondIndex] = (char *)malloc(1); strcpy((*stringData)[dataIndex][secondIndex], ""); break; } break; case IC_CONVERT: // data type must be string to get this (*stringData)[dataIndex][secondIndex] = (char *)malloc(15); sprintf((*stringData)[dataIndex][secondIndex], "%f", cellValue); [self deleteTrailingZeros: (*stringData)[dataIndex][secondIndex]]; break; case IC_ERROR: NX_RAISE(IC_CELLTYPE, NULL, NULL); break; } } dataIndex++; } // send back the number of rows and columns if (byRows) { *numColumns = itemCount; *numRows = dataIndex; } else { *numColumns = dataIndex; *numRows = rowCount; } // free stuff [self freeData:itemNames count:itemCount]; [self freeData:rowNames count:rowCount]; NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: if (*(int *)NXLocalHandler.data1 == imxerr_NO_SELECTION) myReturnCode = WB_NOTHINGSELECTED; else myReturnCode = WB_UNKNOWNERROR; break; case IC_SELECTIONTYPE: myReturnCode = WB_WRONGTYPEOFSELECTION; break; case IC_GETRANGE: free(selection); myReturnCode = WB_UNKNOWNERROR; break; case IC_GETROWS: [self freeData:itemNames count:itemCount]; [self freeData:rowNames count:rowCount]; break; case IC_GETCELLVALUE: [self freeData:itemNames count:itemCount]; [self freeData:rowNames count:rowCount]; switch (dataType) { case WB_DOUBLEDATA: [self freeData:*doubleData count:dataIndex]; break; case WB_FLOATDATA: [self freeData:*floatData count:dataIndex]; break; case WB_INTDATA: [self freeData:*intData count:dataIndex]; break; case WB_STRINGDATA: [self freeStringData:*stringData counts:dataIndex-1 :secondCount]; if (secondIndex > 0) [self freeData:(*stringData)[dataIndex] count:secondIndex]; break; } myReturnCode = WB_UNKNOWNERROR; break; case IC_CELLTYPE: [self freeData:itemNames count:itemCount]; [self freeData:rowNames count:rowCount]; switch (dataType) { case WB_DOUBLEDATA: [self freeData:*doubleData count:dataIndex]; break; case WB_FLOATDATA: [self freeData:*floatData count:dataIndex]; break; case WB_INTDATA: [self freeData:*intData count:dataIndex]; break; case WB_STRINGDATA: [self freeStringData:*stringData counts:dataIndex-1 :secondCount]; if (secondIndex > 0) [self freeData:(*stringData)[dataIndex] count:secondIndex]; break; } myReturnCode = WB_WRONGCELLTYPE; break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)fillColumnsCount:(int)numColumns startingAt:(char *)columnName withDoubleData:(double **)data byRows:(BOOL)byRows dataCount:(int)numRows { return [self fillColumnsCount:numColumns startingAt:columnName withDataType:WB_DOUBLEDATA double:data float:NULL int:NULL string:NULL byRows:byRows dataCount:numRows]; } - (int)fillColumnsCount:(int)numColumns startingAt:(char *)columnName withFloatData:(float **)data byRows:(BOOL)byRows dataCount:(int)numRows { return [self fillColumnsCount:numColumns startingAt:columnName withDataType:WB_FLOATDATA double:NULL float:data int:NULL string:NULL byRows:byRows dataCount:numRows]; } - (int)fillColumnsCount:(int)numColumns startingAt:(char *)columnName withIntData:(int **)data byRows:(BOOL)byRows dataCount:(int)numRows { return [self fillColumnsCount:numColumns startingAt:columnName withDataType:WB_INTDATA double:NULL float:NULL int:data string:NULL byRows:byRows dataCount:numRows]; } - (int)fillColumnsCount:(int)numColumns startingAt:(char *)columnName withStringData:(char ***)data byRows:(BOOL)byRows dataCount:(int)numRows { return [self fillColumnsCount:numColumns startingAt:columnName withDataType:WB_STRINGDATA double:NULL float:NULL int:NULL string:data byRows:byRows dataCount:numRows]; } - (int)fillColumnsCount:(int)numColumns startingAt:(char *)columnName withDataType:(int)dataType double:(double **)doubleData float:(float **)floatData int:(int **)intData string:(char ***)stringData byRows:(BOOL)byRows dataCount:(int)numRows { char *selName, *viewName, *sheetName, *modelName, *lastRow, *firstRow; char *parent, **rowNames, cellName[500], *parentName, *categoryList; char **categoryNames, *cellString, *rowCategory, **columnNames; char **fillColumnNames; imxSelType selType; imxCellType cellType; int imxReturnCode, myReturnCode = 0, rowCount, rowIndex, categoryCount; int colIndex, colCount; BOOL found; double cellValue; NX_DURING // make sure the starting column really exists and get its category // get the current sheet and model if ((imxReturnCode = imxGetSelection(&selName, &selType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); strcpy(sheet, sheetName); strcpy(model, modelName); // make sure we can find the given column and that it is a column if ((imxReturnCode = imxGetItemInfo(&parentName, &firstRow, &lastRow, columnName, sheet, model)) != 0) NX_RAISE(IC_GETINFO, &imxReturnCode, NULL); if (parentName == NULL) NX_RAISE(IC_COLUMNCHECK, &imxReturnCode, NULL); parent = (char *)malloc(strlen(parentName) + 1); strcpy(parent, parentName); if ((imxReturnCode = imxGetCategoryList(&categoryList, sheet, model)) != 0) NX_RAISE(IC_GETCATEGORIES, &imxReturnCode, NULL); [self getNames:&categoryNames fromList:categoryList count:&categoryCount]; for (rowIndex = 0, found = NO; rowIndex < categoryCount; rowIndex++) if (strcmp(categoryNames[rowIndex], parent) == 0) found = YES; else { rowCategory = (char *)malloc (strlen(categoryNames[rowIndex]) + 1); strcpy(rowCategory, categoryNames[rowIndex]); } [self freeData:categoryNames count:categoryCount]; if (!found) { free(parent); NX_RAISE(IC_COLUMNCHECK, NULL, NULL); } // get the list of rows for the given column if ((myReturnCode = [self getRows:&rowNames rowCount:&rowCount forColumnCategory:parent]) != 0) NX_RAISE(IC_GETROWS, NULL, NULL); // if there aren't enough rows for the data, add some at the end if (rowCount < numRows) if ((myReturnCode = [self addColumns:NULL count:numRows-rowCount afterColumn:rowNames[rowCount-1]]) != 0) NX_RAISE(IC_ADDCOLUMNS, NULL, NULL); [self freeData:rowNames count:rowCount]; if ((myReturnCode = [self getRows:&rowNames rowCount:&rowCount forColumnCategory:parent]) != 0) NX_RAISE(IC_GETROWS, NULL, NULL); // get the list of column names, make sure there are enough if ((myReturnCode = [self getRows:&columnNames rowCount:&colCount forColumnCategory:rowCategory]) != 0) NX_RAISE(IC_GETCOLUMNS, NULL, NULL); for (colIndex = 0, found = NO; (colIndex < colCount) && !found; colIndex++) if (strcmp(columnNames[colIndex], columnName) == 0) { fillColumnNames = columnNames + colIndex; found = YES; } free(parent); if (colCount - colIndex + 1 < numColumns) NX_RAISE(IC_NUMBERCOLUMNS, NULL, NULL); // insert the data into the columns if (dataType == WB_STRINGDATA) { cellType = cval_TEXT; cellValue = 0; } else { cellType = cval_NUMBER; cellString = (char *)malloc(1); strcpy(cellString, ""); } for (rowIndex = 0; rowIndex < numRows; rowIndex++) for (colIndex = 0; colIndex < numColumns; colIndex++) { switch (dataType) { case WB_DOUBLEDATA: cellValue = doubleData[rowIndex][colIndex]; break; case WB_FLOATDATA: cellValue = floatData[rowIndex][colIndex]; break; case WB_INTDATA: cellValue = intData[rowIndex][colIndex]; break; case WB_STRINGDATA: cellString = (char *)malloc (strlen(stringData[rowIndex][colIndex]) + 1); strcpy(cellString, stringData[rowIndex][colIndex]); break; } sprintf(cellName, "%s:%s", fillColumnNames[colIndex], rowNames[rowIndex]); if ((imxReturnCode = imxSetCellValue(cellName, cellType, cellValue, cellString, sheet, model)) != 0) NX_RAISE(IC_SETCELLVALUE, &imxReturnCode, NULL); } if ((imxReturnCode = imxUpdateModel(model)) != 0) NX_RAISE(IC_UPDATE, &imxReturnCode, NULL); // free stuff [self freeData:rowNames count:rowCount]; [self freeData:columnNames count:colCount]; NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: myReturnCode = WB_UNKNOWNERROR; break; case IC_GETINFO: if (*(int *)NXLocalHandler.data1 == imxerr_ITEM_NOT_FOUND) myReturnCode = WB_NOSUCHCOLUMN; else myReturnCode = WB_UNKNOWNERROR; break; case IC_GETCATEGORIES: free(parent); myReturnCode = WB_UNKNOWNERROR; break; case IC_GETROWS: free(parent); break; case IC_ADDCOLUMNS: free(parent); [self freeData:rowNames count:rowCount]; break; case IC_GETCOLUMNS: free(parent); [self freeData:rowNames count:rowCount]; break; case IC_COLUMNCHECK: myReturnCode = WB_NOSUCHCOLUMN; break; case IC_NUMBERCOLUMNS: [self freeData:rowNames count:rowCount]; [self freeData:columnNames count:colCount]; myReturnCode = WB_NOTENOUGHCOLUMNS; break; case IC_SETCELLVALUE: case IC_UPDATE: [self freeData:rowNames count:rowCount]; [self freeData:columnNames count:colCount]; myReturnCode = WB_UNKNOWNERROR; break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)addColumns:(char **)newColumns count:(int)numColumns afterColumn:(char *)existingColumn { imxSelType selectionType = imxsel_ITEM, oldType; char *viewName, *sheetName, *modelName, *selection, *view, **columnNames; int imxReturnCode, myReturnCode = 0, numCols, colIndex; NX_DURING // get the view, sheet, and model if ((imxReturnCode = imxGetSelection(&selection, &oldType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); view = (char *)malloc(strlen(viewName)+1); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); strcpy(view, viewName); strcpy(sheet, sheetName); strcpy(model, modelName); // select it the given column if ((imxReturnCode = imxSetSelection(existingColumn, selectionType, view, sheet, model)) != 0) NX_RAISE(IC_SETSELECTION, &imxReturnCode, NULL); free(view); // create the new columns if ((imxReturnCode = imxAddItems(NULL, numColumns, ipos_AFTER)) != 0) NX_RAISE(IC_ADDITEMS, NULL, NULL); // rename the new columns if (newColumns) { [self getSelectedColumnNames:&columnNames count:&numCols]; for (colIndex = 0; colIndex < numCols; colIndex++) if ((imxReturnCode = imxRename(newColumns[colIndex], imxsel_ITEM, columnNames[colIndex], sheet, model)) != 0) NX_RAISE(IC_RENAME, &imxReturnCode, NULL); [self freeData:columnNames count:numCols]; } NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: myReturnCode = WB_UNKNOWNERROR; break; case IC_SETSELECTION: free(view); if (*(int *)NXLocalHandler.data1 == imxerr_NO_SELECTION) myReturnCode = WB_NOSUCHCOLUMN; else myReturnCode = WB_UNKNOWNERROR; break; case IC_ADDITEMS: myReturnCode = WB_UNKNOWNERROR; break; case IC_RENAME: [self freeData:columnNames count:numCols]; myReturnCode = WB_UNKNOWNERROR; break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)getSelectedColumnNames:(char ***)columnNames count:(int *)numColumns { imxSelType selectionType; char *viewName, *sheetName, *modelName, *selectionName, *parentName; int imxReturnCode, myReturnCode = 0; char *columnList, *selection; NX_DURING // get the selection information if ((imxReturnCode = imxGetSelection(&selectionName, &selectionType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); selection = (char *)malloc(strlen(selectionName)+1); strcpy(sheet, sheetName); strcpy(model, modelName); strcpy(selection, selectionName); // get a list of the names in the selected range if (selectionType == imxsel_ITEM) { if ((imxReturnCode = imxGetItemRangeInfo(&parentName, &columnList, selection, sheet, model)) != 0) NX_RAISE(IC_GETINFO, &imxReturnCode, NULL); [self getNames:columnNames fromList:columnList count:numColumns]; } else NX_RAISE(IC_SELECTIONTYPE, &imxReturnCode, NULL); free(selection); NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: if (*(int *)NXLocalHandler.data1 == imxerr_NO_SELECTION) myReturnCode = WB_NOTHINGSELECTED; else myReturnCode = WB_UNKNOWNERROR; break; case IC_GETINFO: free(selection); myReturnCode = WB_UNKNOWNERROR; break; case IC_SELECTIONTYPE: free(selection); myReturnCode = WB_WRONGTYPEOFSELECTION; break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)makeNewWorksheet:(char *)worksheetName numRows:(int)numRows numCols:(int)numColumns rowNames:(char **)rowNames colNames:(char **)columnNames { imxSelType selectionType; char *viewName, *sheetName, *modelName, *selection; int imxReturnCode, myReturnCode = 0; NX_DURING // return if number of rows or columns is zero if ((numRows <= 0) || (numColumns <= 0)) NX_RAISE(IC_BADPARAMETERS, NULL, NULL); // create the new worksheet, rename it, get the sheet and model names if ((imxReturnCode = imxCmdExec(imxcmd_NEWSHEET)) != 0) NX_RAISE(IC_NEWSHEET, &imxReturnCode, NULL); if ((imxReturnCode = imxGetSelection(&selection, &selectionType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); strcpy(sheet, sheetName); strcpy(model, modelName); if (worksheetName) { if ((imxReturnCode = imxRename(worksheetName, imxsel_SHEET, sheet, sheet, model)) != 0) NX_RAISE(IC_RENAME, &imxReturnCode, NULL); if ((imxReturnCode = imxGetSelection(&selection, &selectionType, &viewName, &sheetName, &modelName)) != 0) NX_RAISE(IC_GETSELECTION, &imxReturnCode, NULL); sheet = (char *)realloc(sheet, strlen(sheetName)+1); model = (char *)realloc(model, strlen(modelName)+1); strcpy(sheet, sheetName); strcpy(model, modelName); } // add and name columns if (numColumns > 1) if (columnNames) { if ((myReturnCode = [self addColumns:columnNames+1 count:numColumns-1 afterColumn:"B1"]) != 0) NX_RAISE(IC_ADDCOLUMNS, NULL, NULL); } else if ((myReturnCode = [self addColumns:NULL count:numColumns-1 afterColumn:"B1"]) != 0) NX_RAISE(IC_ADDCOLUMNS, NULL, NULL); if (columnNames) if ((imxReturnCode = imxRename(columnNames[0], imxsel_ITEM, "B1", sheet, model)) != 0) NX_RAISE(IC_RENAME, &imxReturnCode, NULL); // add rows and name rows if (numRows > 1) if (rowNames) { if ((myReturnCode = [self addColumns:rowNames+1 count:numRows-1 afterColumn:"A1"]) != 0) NX_RAISE(IC_ADDCOLUMNS, NULL, NULL); } else if ((myReturnCode = [self addColumns:NULL count:numRows-1 afterColumn:"A1"]) != 0) NX_RAISE(IC_ADDCOLUMNS, NULL, NULL); if (rowNames) if ((imxReturnCode = imxRename(rowNames[0], imxsel_ITEM, "A1", sheet, model)) != 0) NX_RAISE(IC_RENAME, &imxReturnCode, NULL); NX_HANDLER switch (NXLocalHandler.code) { case IC_GETSELECTION: myReturnCode = WB_UNKNOWNERROR; break; case IC_BADPARAMETERS: myReturnCode = WB_UNKNOWNERROR; break; case IC_ADDITEMS: myReturnCode = WB_UNKNOWNERROR; break; case IC_NEWSHEET: myReturnCode = WB_UNKNOWNERROR; break; case IC_RENAME: myReturnCode = WB_UNKNOWNERROR; break; case IC_ADDCOLUMNS: break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - getNames:(char ***)names fromList:(char *)list count:(int *)numNames { int nameIndex; char *nameStart, *nameEnd; // splits a \n-separated list into separate strings for ((*numNames) = 0, nameStart = list; *nameStart; nameStart = strchr(nameStart, '\n') + 1, (*numNames)++); *names = (char **)malloc((*numNames) * sizeof(char *)); nameStart = list; for (nameIndex = 0; nameIndex < *numNames; nameIndex++) { nameEnd = strchr(nameStart, '\n'); (*names)[nameIndex] = (char *)malloc(nameEnd - nameStart + 1); strncpy((*names)[nameIndex], nameStart, nameEnd - nameStart); (*names)[nameIndex][nameEnd - nameStart] = '\0'; nameStart = nameEnd + 1; } return self; } - (int)getRows:(char ***)rowList rowCount:(int *)numRows forColumnCategory:(char *)columnCategory { char *lastRow, *firstRow; char *categoryList, **categoryNames, *rowCategory, *parentName; char *rowRange, *itemList; int imxReturnCode, myReturnCode = 0, categoryCount; NX_DURING // get a list of all the categories, make sure there aren't more than two if ((imxReturnCode = imxGetCategoryList(&categoryList, sheet, model)) != 0) NX_RAISE(IC_GETCATEGORIES, &imxReturnCode, NULL); [self getNames:&categoryNames fromList:categoryList count:&categoryCount]; if (categoryCount > 2) NX_RAISE(IC_NUMBERCATEGORIES, NULL, NULL); // find which category contains the given item and which doesn't if (strcmp(categoryNames[0], columnCategory) == 0) rowCategory = categoryNames[1]; else if (strcmp(categoryNames[1], columnCategory) == 0) rowCategory = categoryNames[0]; else NX_RAISE(IC_BADCATEGORIES, NULL, NULL); // for the non-given category, get a list of the items in it if ((imxReturnCode = imxGetItemInfo(&parentName, &firstRow, &lastRow, rowCategory, sheet, model)) != 0) NX_RAISE(IC_GETITEMINFO, &imxReturnCode, NULL); [self freeData:categoryNames count:categoryCount]; rowRange = (char *)malloc(strlen(firstRow) + strlen(lastRow) + 3); strcpy(rowRange, firstRow); strcat(rowRange, ".."); strcat(rowRange, lastRow); if ((imxReturnCode = imxGetItemRangeInfo(&parentName, &itemList, rowRange, sheet, model)) != 0) NX_RAISE(IC_GETRANGEINFO, &imxReturnCode, NULL); free(rowRange); [self getNames:rowList fromList:itemList count:numRows]; NX_HANDLER switch (NXLocalHandler.code) { case IC_GETCATEGORIES: myReturnCode = WB_UNKNOWNERROR; break; case IC_NUMBERCATEGORIES: myReturnCode = WB_TOOMANYCATEGORIES; [self freeData:categoryNames count:categoryCount]; break; case IC_BADCATEGORIES: myReturnCode = WB_NOSUCHCOLUMN; [self freeData:categoryNames count:categoryCount]; break; case IC_GETITEMINFO: myReturnCode = WB_UNKNOWNERROR; [self freeData:categoryNames count:categoryCount]; break; case IC_GETRANGEINFO: myReturnCode = WB_UNKNOWNERROR; free(rowRange); break; default: NX_RERAISE(); } NX_ENDHANDLER return myReturnCode; } - (int)handleCell:(int)cellType forData:(int)dataType { int handleAs = IC_ERROR; if (dataType == WB_STRINGDATA) switch (cellType) { case cval_TEXT: handleAs = IC_USEVALUE; break; case cval_EMPTY: handleAs = IC_USEZERO; break; case cval_NUMBER: handleAs = IC_CONVERT; break; default: handleAs = IC_ERROR; } else // data type is numeric switch (cellType) { case cval_NUMBER: handleAs = IC_USEVALUE; break; case cval_TEXT: switch (textCellHandling) { case WB_SKIP: handleAs = IC_SKIPVALUE; break; case WB_ZERO: handleAs = IC_USEZERO; break; case WB_ERROR: handleAs = IC_ERROR; } break; case cval_EMPTY: switch (emptyCellHandling) { case WB_SKIP: handleAs = IC_SKIPVALUE; break; case WB_ZERO: handleAs = IC_USEZERO; break; case WB_ERROR: handleAs = IC_ERROR; } break; default: handleAs = IC_ERROR; } return handleAs; } - deleteTrailingZeros:(char *)formattedNumber { if (strchr(formattedNumber, '.')) { while (formattedNumber[strlen(formattedNumber)-1] == '0') formattedNumber[strlen(formattedNumber)-1] = '\0'; if (formattedNumber[strlen(formattedNumber)-1] == '.') formattedNumber[strlen(formattedNumber)-1] = '\0'; } return self; } - freeData:(void *)data count:(int)count { int index; for (index = 0; index < count; index++) free(((char **)data)[index]); free(data); return self; } - freeStringData:(void *)data counts:(int)count1 :(int)count2 { int index1, index2; for (index1 = 0; index1 < count1; index1++) for (index2 = 0; index2 < count2; index2++) free(((char ***)data)[index1][index2]); for (index1 = 0; index1 < count1; index1++) free(((char ***)data)[index1]); free(data); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.