/***************************************************************************** * Modul : mpsx.c * * Zweck : Einlesen eines files im MPSX-Standardeingabeformat * * Format : load [-cGOAL] [-bRHS] [-rRANGES] [-uBOUNDS] [-m] [-fFILE] * * Autor : Stefan Förster * * * * Datum | Version | Bemerkung * * -----------|---------|--------------------------------------------------- * * 05.03.1989 | 0.0 | * * 07.03.1989 | 0.1 | PrintError() * * 08.03.1989 | 0.2 | Pass1() * * 09.03.1989 | | Pass1() fertig * * 10.03.1989 | 0.3 | Zusätzliche Fehlermeldungen * * | | SearchEl() liefert jetzt den Typ ITEMPTR * * | | ChooseSymbols(), Select() * * 11.03.1989 | 0.4 | Pass2() * * | | Felder GLOBAL definiert * * 13.03.1989 | 0.5 | Pass2() und CorrectBounds() fertig * * | | BUG in ParseLine(): &stop[1] statt &stop[2] * * | | BUG in TakeMem(): AvailMem(NULL) statt AvailMem() * * | | BUG in ParseLine(): list[GOALS_LIST] durchsuchen * * | | BUG in MPSX(): ChooseSymbols() statt ChooseSymbols * * 14.03.1989 | 1.0 | BUG in Pass2(): Wenn symbflag & BIT_RHS, ist * * | | list[RHS_LIST] leer (DeleteList()) * * | | BUG in Pass2(): Fehler bei 2 Zielfkt. behoben * * | | BUG in Pass2(): RANGES: if(++i>num_lines) ... * * | | BUG in Pass2(): RANGES: num_rows+i statt m+i * * | | BUG in Pass2(): Schl.var.: Zeile iptr->nr statt i * * | | BUG in CorrectBounds(): upper[i] -= lower[i]; * * | | 1. Testlauf erfolgreich * * 17.03.1989 | 1.1 | zusätzlich min cTx möglich * * 18.03.1989 | 1.2 | Optional Ausgabe an ein File möglich (-f) * *****************************************************************************/ IMPORT STRPTR ctime(), fgets(); IMPORT VOID *AllocMem(), fclose(), SetM(), CopyMemQuick(); IMPORT FILE *fopen(); IMPORT INT fseek(); IMPORT LONG ftell(), time(); GLOBAL DOUBLE INFINITE; GLOBAL BOOL minimize; GLOBAL DOUBLE c0start, c0; GLOBAL SHORT m, n, *B, *Nq; GLOBAL DOUBLE *A, *AB1, *b, *b2q, *c, *c2, *upper, *lower; GLOBAL DOUBLE *x, *cq, *pi, *dq; GLOBAL SHORT *Nminus; GLOBAL DOUBLE *help; GLOBAL STRPTR errors[]; USHORT symbflag; GLOBAL TEXT symbols[NUM_SYMBOLS][MAX_STRLEN+1]; TEXT filename[MAX_FILELEN+1]; GLOBAL FILE *file[2]; struct stat file_stat; GLOBAL ITEMPTR list[NUM_LISTS]; LONG position[NUM_SYMBOLS]; SHORT num_var, num_slack, num_rows, num_lines, num_goals, num_rhs; SHORT num_ranges, num_bounds; LONG mm, nn; TEXT line_nr[9]; /* Zählvariable, max 99999999 (8 Zeichen) */ TEXT line[BUFFER]; /* eingelesene Zeile */ TEXT buf[4][BUFFER2+1]; /* Zwischenspeicher */ /***************************************************************************** * BOOL MPSX() -> _TRUE/_FALSE * * Hauptprogramm von MPSX.c * * * * Input: args : Zeiger auf Argument-String (hinter load) * * * * Output: _FALSE : Fehler beim Einlesen * * _TRUE : c0start: Korrekturwert für den Zielfunktionswert * * m,n: m und n * * Zeiger auf A,AB1,etc. * *****************************************************************************/ BOOL MPSX(args) STRPTR args; { SHORT i; BOOL GetArgs(), Pass1(), Pass2(), ChooseSymbols(), CorrectBounds(); VOID GetRidOfLists(), GiveMemBack(); num_var = num_goals = num_rhs = num_ranges = num_bounds = 0; num_slack = num_rows = num_lines = 0; GetRidOfLists(); for(i=0; i _TRUE/_FALSE * * wertet den Argument-String hinter load aus und setzt symbflag und * * symbols[][] entsprechend * * _TRUE : O.K. (file wurde geöffnet) * * _FALSE : Fehler aufgetreten * *****************************************************************************/ BOOL GetArgs(str) STRPTR str; { SHORT start, stop, length; LONG t; TEXT ch; VOID PrintError(), Cap(); BOOL SearchExpr(); SHORT GetExpr(); STRPTR ptr; symbflag = 0; if(!SearchExpr(str,&start,&stop)) { PrintError(ERR_INVALID_ARGS,NULL); return(_FALSE); } else { /* file-Name gefunden */ length = GetExpr(filename,str,start,stop); if(length > MAX_FILELEN) { PrintError(ERR_FILE_TOO_LONG,filename); return(_FALSE); } else { /* und hat korrekte Länge */ if(!(file[0] = fopen(filename,"r"))) { PrintError(errno,filename); PrintError(ERR_NOT_READ,filename); return(_FALSE); } } } /* Jetzt die Argumente */ ptr = str+stop+1; while(SearchExpr(ptr,&start,&stop)) { Cap(ptr,start,stop); if((length = stop-start-1)==0 && strncmp(ptr+start,"-M",2)==0) minimize = _TRUE; else if(length > 0 && strncmp(ptr+start,"-F",2) == 0) { length = GetExpr(buf[0],ptr,start+2,stop); if(length > MAX_FILELEN) { PrintError(ERR_FILE_TOO_LONG,buf[0]); return(_FALSE); } if(!(file[1] = fopen(buf[0],"w"))) { PrintError(errno,buf[0]); PrintError(ERR_NOT_WRITE,buf[0]); return(_FALSE); } fputs("ASimplex Version 1.2\n",file[1]); fputs("THE Amiga Simplex Program\n",file[1]); fputs("(c) 18.03.1989 Stefan Förster\n\n",file[1]); t = time(NULL); fprintf(file[1],"Hardcopy on %s\n",ctime(&t)); } else { if(length <= 0) goto invalid; /* (stop-start+1)-2 */ if(length > MAX_STRLEN) { *(ptr+stop+1) = '\0'; PrintError(ERR_NAME_TOO_LONG,ptr+start+2); return(_FALSE); } if(strncmp(ptr+start,"-C",2) == 0) { if(symbflag & BIT_GOAL) goto invalid; /* zwei Zielfkt. angegeben */ else { symbflag |= BIT_GOAL; strncpy(symbols[GOAL],ptr+start+2,length); symbols[GOAL][length] = '\0'; } } else if(strncmp(ptr+start,"-B",2) == 0) { if(symbflag & BIT_RHS) goto invalid; else { symbflag |= BIT_RHS; strncpy(symbols[RHS],ptr+start+2,length); symbols[RHS][length] = '\0'; } } else if(strncmp(ptr+start,"-R",2) == 0) { if(symbflag & BIT_RANGES) goto invalid; else { symbflag |= BIT_RANGES; strncpy(symbols[RANGES],ptr+start+2,length); symbols[RANGES][length] = '\0'; } } else if(strncmp(ptr+start,"-U",2) == 0) { if(symbflag & BIT_BOUNDS) goto invalid; else { symbflag |= BIT_BOUNDS; strncpy(symbols[BOUNDS],ptr+start+2,length); symbols[BOUNDS][length] = '\0'; } } else goto invalid; } ptr += stop+1; } /* while() */ if(stat(filename,&file_stat) == -1) { PrintError(errno,filename); return(_FALSE); } else { printf("== loading %s %ld bytes\n",filename,file_stat.st_size); printf(" %s",ctime(&file_stat.st_mtime)); } return(_TRUE); invalid: /* Sprungmarke (na ja) für "invalid arguments" */ PrintError(ERR_INVALID_ARGS,NULL); return(_FALSE); } /***************************************************************************** * BOOL Pass1() -> _TRUE/_FALSE * * Pass1() durchläuft zum ersten Mal. Es werden Listen der Variablen, * * der rechten Seiten (falls noch nicht festgelegt) usw. angelegt. Außerdem * * erfolgt eine Syntaxüberprüfung. * * _TRUE : OK * * _FALSE : Fehler aufgetreten * *****************************************************************************/ BOOL Pass1() { LONG count = 0, pos; SHORT start[5], stop[5], length; USHORT found = 0, actual = 0; TEXT ch; STRPTR ptr[5]; ITEMPTR iptr; BOOL SearchExpr(), ParseLine(); VOID PrintError(), UpdateLine(); SHORT GetExpr(); ITEMPTR NewListEl(), SearchEl(); printf("P1 0"); sprintf(line_nr,"%ld",count); ptr[0] = line; /* 1. Sektion muß "NAME" sein */ do { if(!fgets(ptr[0],BUFFER-1,file[0])) { if(feof(file[0])) goto finish; if(ferror(file[0])) { puts(""); PrintError(errno,NULL); return(_FALSE); } } UpdateLine(&count); pos = ftell(file[0]); Cap(ptr[0],0,BUFFER); } while(!SearchExpr(ptr[0],&start[0],&stop[0])); length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(start[0] != 0) { puts(""); PrintError(ERR_SECTIONS,buf[0]); PrintError(ERR_NO_NAME,buf[0]); return(_FALSE); } if(length != 4 || strncmp(buf[0],"NAME",4) != 0) { puts(""); PrintError(ERR_NO_NAME,buf[0]); return(_FALSE); } if(!SearchExpr((ptr[1]=ptr[0]+stop[0]+1),&start[1],&stop[1])) { puts(""); PrintError(ERR_NO_NAME,NULL); return(_FALSE); } length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[1]); return(_FALSE); } symbflag |= BIT_NAME; found |= BIT_NAME; strcpy(symbols[NAME],buf[1]); position[NAME] = pos; /* Jetzt folgen die anderen Sektionen */ FOREVER { if(feof(file[0])) goto finish; if(!fgets(ptr[0],BUFFER-1,file[0])) { if(ferror(file[0])) { puts(""); PrintError(errno,NULL); return(_FALSE); } } UpdateLine(&count); pos = ftell(file[0]); Cap(ptr[0],0,BUFFER); if(!SearchExpr(ptr[0],&start[0],&stop[0])) continue; /* FOREVER */ length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[0]); return(_FALSE); } if(start[0] == 0) { /* Start einer neuen Sektion */ if(length==6 && strncmp(buf[0],"ENDATA",6) == 0) { found |= BIT_ENDATA; goto finish; } else if(length==4 && strncmp(buf[0],"ROWS",4) == 0) { if(found & BIT_ROWS) { puts(""); PrintError(ERR_2SECTIONS,buf[0]); return(_FALSE); } else { found |= BIT_ROWS; actual = BIT_ROWS; position[ROWS] = pos; continue; } } else if(length==7 && strncmp(buf[0],"COLUMNS",7) == 0) { if(found & BIT_COLUMNS) { puts(""); PrintError(ERR_2SECTIONS,buf[0]); return(_FALSE); } else { found |= BIT_COLUMNS; actual = BIT_COLUMNS; position[COLUMNS] = pos; continue; } } else if(length==3 && strncmp(buf[0],"RHS",3) == 0) { if(found & BIT_RHS) { puts(""); PrintError(ERR_2SECTIONS,buf[0]); return(_FALSE); } else { found |= BIT_RHS; actual = BIT_RHS; position[RHS] = pos; continue; } } else if(length==6 && strncmp(buf[0],"RANGES",6) == 0) { if(found & BIT_RANGES) { puts(""); PrintError(ERR_2SECTIONS,buf[0]); return(_FALSE); } else { found |= BIT_RANGES; actual = BIT_RANGES; position[RANGES] = pos; continue; } } else if(length==6 && strncmp(buf[0],"BOUNDS",6) == 0) { if(found & BIT_BOUNDS) { puts(""); PrintError(ERR_2SECTIONS,buf[0]); return(_FALSE); } else { found |= BIT_BOUNDS; actual = BIT_BOUNDS; position[BOUNDS] = pos; continue; } } else { puts(""); PrintError(ERR_UNKNOWN_SEC,buf[0]); return(_FALSE); } } /* if(start[0]==0) */ else { /* if(start[0]!=0) */ if(actual == 0) { puts(""); PrintError(ERR_SECTIONS,buf[0]); return(_FALSE); } switch(actual) { case BIT_ROWS: if(length!=1 || (ch = buf[0][0])!='N' && ch!='E' && ch!='L' && ch!='G') { puts(""); PrintError(ERR_INV_ROWS_TYPE,buf[0]); return(_FALSE); } ptr[1] = ptr[0]+start[0]+1; if(!SearchExpr(ptr[1],&start[1],&stop[1])) { puts(""); PrintError(ERR_MISSING,NULL); return(_FALSE); } length = GetExpr(buf[0]+1,ptr[1],start[1],stop[1]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[0]+1); return(_FALSE); } if(ch == 'N') { /* Zielfunktion */ if(SearchEl(buf[0]+1,list[GOALS_LIST],_FALSE,NULL)) { puts(""); PrintError(ERR_DOUBLE,buf[0]+1); return(_FALSE); } if(!(iptr = NewListEl(list[GOALS_LIST],buf[0]+1))) return(_FALSE); else { if(list[GOALS_LIST]) iptr->nr = list[GOALS_LIST]->nr+1; else iptr->nr = 1; list[GOALS_LIST] = iptr; ++num_goals; } } else { /* Typ L, G oder E */ if(SearchEl(buf[0]+1,list[ROWS_LIST],_TRUE,NULL)) { puts(""); PrintError(ERR_DOUBLE,buf[0]+1); return(_FALSE); } if(!(iptr = NewListEl(list[ROWS_LIST],buf[0]))) return(_FALSE); else { if(list[ROWS_LIST]) iptr->nr = list[ROWS_LIST]->nr+1; else iptr->nr = 1; list[ROWS_LIST] = iptr; ++num_rows; if(ch == 'L' || ch == 'G') ++num_slack; } } break; case BIT_COLUMNS: if(!ParseLine(VAR_LIST,buf[0],stop[0])) return(_FALSE); break; case BIT_RHS: if(!ParseLine(RHS_LIST,buf[0],stop[0])) return(_FALSE); break; case BIT_RANGES: if(!ParseLine(RANGES_LIST,buf[0],stop[0])) return(_FALSE); break; case BIT_BOUNDS: if(length!=2 || (strncmp(buf[0],"UP",2)!=0 && strncmp(buf[0],"LO",2)!=0)) { puts(""); PrintError(ERR_INV_BOUNDS_TYPE,buf[0]); return(_FALSE); } /* Jetzt müssen drei Ausdrücke folgen */ if(!SearchExpr((ptr[1]=ptr[0]+stop[0]+1),&start[1],&stop[1]) || !SearchExpr((ptr[2]=ptr[1]+stop[1]+1),&start[2],&stop[2]) || !SearchExpr((ptr[3]=ptr[2]+stop[2]+1),&start[3],&stop[3]) ) { puts(""); PrintError(ERR_MISSING,NULL); return(_FALSE); } length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[1]); return(_FALSE); } if(!SearchEl(buf[1],list[BOUNDS_LIST],_FALSE,NULL)) { if(!(iptr = NewListEl(list[BOUNDS_LIST],buf[1]))) return(_FALSE); else { if(list[BOUNDS_LIST]) iptr->nr = list[BOUNDS_LIST]->nr+1; else iptr->nr = 1; list[BOUNDS_LIST] = iptr; ++num_bounds; } } length = GetExpr(buf[2],ptr[2],start[2],stop[2]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[2]); return(_FALSE); } if(!SearchEl(buf[2],list[VAR_LIST],_FALSE,NULL)) { puts(""); PrintError(ERR_UNKNOWN_ID,buf[2]); return(_FALSE); } break; } /* switch(actual) */ } /* else if(start[0]!=0) */ } /* FOREVER() */ finish: /* Sprungmarke, falls feof(file[0]) oder ENDATA erreicht */ if(!(found & BIT_ROWS) || num_rows == 0) { puts(""); PrintError(ERR_NO_ROWS,NULL); return(_FALSE); } if(!(found & BIT_COLUMNS) || num_var == 0) { puts(""); PrintError(ERR_NO_COLUMNS,NULL); return(_FALSE); } if(!(found & BIT_RHS)) { puts(""); PrintError(ERR_NO_RHS,NULL); return(_FALSE); } if(!(found & BIT_ENDATA)) { puts(""); PrintError(ERR_NO_ENDATA,NULL); return(_FALSE); } if(position[NAME] >= position[ROWS] || position[ROWS] >= position[COLUMNS] || position[COLUMNS] >= position[RHS] || position[RANGES] != -1 && position[BOUNDS] != -1 && position[RANGES] >= position[BOUNDS] ) { puts(""); PrintError(ERR_ORDER,NULL); return(_FALSE); } puts(""); return(_TRUE); /* alle Fehlerfälle überstanden */ } /***************************************************************************** * VOID UpdateLine() * * Aktualisiert den Zeilenzähler von Pass1() * *****************************************************************************/ VOID UpdateLine(c) LONG *c; { SHORT i, len = strlen(line_nr); for(i=0; i _TRUE/_FALSE * * Überprüft eine Zeile (aus der Sektion COLUMNS, RHS oder RANGES) auf * * korrekte Syntax. bufptr ist Zeiger auf den Puffer, der den ersten Aus- * * druck der Zeile enthält. Falls dieser noch nicht in der jeweiligen Liste * * enthalten ist, wird er angefügt. list_type kann die Werte VAR_LIST, * * RHS_LIST oder RANGES_LIST annehmen. end0 ist stop[0] von Pass1() * * _TRUE : O.K. * * _FALSE : Fehler aufgetreten * *****************************************************************************/ BOOL ParseLine(list_type,bufptr,end0) SHORT list_type; STRPTR bufptr; SHORT end0; { SHORT start[5], stop[5], length; TEXT ch; STRPTR ptr[5]; ITEMPTR iptr, dptr; ITEMPTR NewListEl(), SearchEl(); ptr[0] = line; /* wie auch in Pass1() */ if(!(dptr = SearchEl(bufptr,list[list_type],_FALSE,NULL))) { /* neue Var. */ if(!(iptr = NewListEl(list[list_type],bufptr))) return(_FALSE); else { if(list[list_type]) iptr->nr = list[list_type]->nr+1; else iptr->nr = 1; if(list_type == RANGES_LIST) iptr->anz = 0; list[list_type] = iptr; switch(list_type) { case VAR_LIST: ++num_var; break; case RHS_LIST: ++num_rhs; break; case RANGES_LIST: ++num_ranges; break; } dptr = iptr; } } /* dptr zeigt jetzt auf den 1.Eintrag der Zeile */ ptr[1] = ptr[0]+end0+1; /* mind. 2 Ausdrücke in dieser Zeile */ if(!SearchExpr(ptr[1],&start[1],&stop[1]) || !SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2])) { puts(""); PrintError(ERR_MISSING,NULL); return(_FALSE); } length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[1]); return(_FALSE); } ch = '\0'; if(!SearchEl(buf[1],list[ROWS_LIST],_TRUE,&ch) && !SearchEl(buf[1],list[GOALS_LIST],_FALSE,NULL) ) { puts(""); PrintError(ERR_UNKNOWN_ID,buf[1]); return(_FALSE); } if(list_type == RANGES_LIST && ch == 'E') { puts(""); PrintError(ERR_INV_RANGES,buf[1]); return(_FALSE); } if(list_type == RANGES_LIST) ++dptr->anz; ptr[3] = ptr[2]+stop[2]+1; /* noch mehr (genau 2) ? */ if(SearchExpr(ptr[3],&start[3],&stop[3])) { ptr[4] = ptr[3]+stop[3]+1; if(!SearchExpr(ptr[4],&start[4],&stop[4])) { puts(""); PrintError(ERR_MISSING,NULL); return(_FALSE); } else { length = GetExpr(buf[3],ptr[3],start[3],stop[3]); if(length > MAX_STRLEN) { puts(""); PrintError(ERR_NAME_TOO_LONG,buf[3]); return(_FALSE); } ch = '\0'; if(!SearchEl(buf[3],list[ROWS_LIST],_TRUE,&ch) && !SearchEl(buf[3],list[GOALS_LIST],_FALSE,NULL) ) { puts(""); PrintError(ERR_UNKNOWN_ID,buf[3]); return(_FALSE); } if(list_type == RANGES_LIST && ch == 'E') { puts(""); PrintError(ERR_INV_RANGES,buf[1]); return(_FALSE); } if(list_type == RANGES_LIST) ++dptr->anz; } } return(_TRUE); } /***************************************************************************** * BOOL ChooseSymbols() -> _TRUE/_FALSE * * Legt endgültig die Bezeichner der Zielfunktion, der rechten Seite, des * * Bereichs und der Grenzen fest. Außerdem wird num_lines ermittelt. * * _TRUE : O.K. * * _FALSE : Fehler aufgetreten * *****************************************************************************/ BOOL ChooseSymbols() { ITEMPTR dptr; ITEMPTR Select(), SearchEl(); VOID DeleteList(); if(!(symbflag & BIT_GOAL)) { if(num_goals == 0) { PrintError(ERR_NO_GOAL,NULL); return(_FALSE); } else if(num_goals == 1) { strcpy(symbols[GOAL],list[GOALS_LIST]->string); symbflag |= BIT_GOAL; } else { if(!(dptr = Select(list[GOALS_LIST],"Possible goals"))) return(_FALSE); else { strcpy(symbols[GOAL],dptr->string); symbflag |= BIT_GOAL; } } } else if(!SearchEl(symbols[GOAL],list[GOALS_LIST],_FALSE,NULL)) { PrintError(ERR_NO_GOAL,NULL); return(_FALSE); } DeleteList(&list[GOALS_LIST]); /* Ist Zielfunktion schon als normale Zeile deklariert ? */ if(SearchEl(symbols[GOAL],list[ROWS_LIST],_TRUE,NULL)) { PrintError(ERR_DOUBLE,symbols[GOAL]); return(_FALSE); } if(!(symbflag & BIT_RHS) && num_rhs>0) { if(num_rhs == 1) { strcpy(symbols[RHS],list[RHS_LIST]->string); symbflag |= BIT_RHS; } else { if(!(dptr = Select(list[RHS_LIST],"Possible right hand sides"))) return(_FALSE); else { strcpy(symbols[RHS],dptr->string); symbflag |= BIT_RHS; } } } DeleteList(&list[RHS_LIST]); if(symbflag & BIT_RANGES) { if(dptr = SearchEl(symbols[RANGES],list[RANGES_LIST],_FALSE,NULL)) num_lines = dptr->anz; else num_lines = 0; } else { if(num_ranges == 0) num_lines = 0; else if(num_ranges == 1) { strcpy(symbols[RANGES],list[RANGES_LIST]->string); symbflag |= BIT_RANGES; num_lines = list[RANGES_LIST]->anz; } else { if(!(dptr = Select(list[RANGES_LIST],"Possible ranges"))) return(_FALSE); else { strcpy(symbols[RANGES],dptr->string); symbflag |= BIT_RANGES; num_lines = dptr->anz; } } } DeleteList(&list[RANGES_LIST]); if(!(symbflag & BIT_BOUNDS) && num_bounds>0) { if(num_bounds == 1) { strcpy(symbols[BOUNDS],list[BOUNDS_LIST]->string); symbflag |= BIT_BOUNDS; } else { if(!(dptr = Select(list[BOUNDS_LIST],"Possible bounds"))) return(_FALSE); else { strcpy(symbols[BOUNDS],dptr->string); symbflag |= BIT_BOUNDS; } } } DeleteList(&list[BOUNDS_LIST]); return(_TRUE); } /***************************************************************************** * ITEMPTR Select(lptr,str) * * Auswahl eines Eintrags der Liste lptr durch den Benutzer. * * Ergebnis ist der Zeiger auf den gewählten Eintrag, NULL, falls ein Fehler * * aufgetreten ist. lptr != NULL wird angenommen. Zu Beginn wird der String * * str ausgegeben. * *****************************************************************************/ ITEMPTR Select(lptr,str) ITEMPTR lptr; STRPTR str; { ITEMPTR ptr = lptr; SHORT count = 0, atoi(), choice, i; INT GetInput(), error; printf("?? %s:\n",str); while(ptr) { printf(" %-8s %3d\n",ptr->string,++count); ptr = ptr->next; } do { printf("?? Your choice : "); if(error = GetInput(line)) { PrintError(error,NULL); return(NULL); } } while((choice = atoi(line)) <= 0 || choice > count); ptr = lptr; for(i=1; inext; return(ptr); } /***************************************************************************** * BOOL Pass2() -> _TRUE/_FALSE * * Pass2() stellt den Speicherplatz bereit und liest die Daten in die er- * * zeugten Felder ein. * * _TRUE : O.K. * * _FALSE : Fehler aufgetreten * *****************************************************************************/ BOOL Pass2() { TEXT ch; SHORT i, j, count, start[5], stop[5], length; STRPTR ptr[5]; ITEMPTR iptr; DOUBLE *ptr1, *ptr2; ITEMPTR SearchEl(); SHORT GetExpr(); BOOL TakeMem(), SearchExpr(); VOID Cap(); DOUBLE atof(); ptr[0] = line; m = num_rows+num_lines; n = num_var+num_slack+num_lines; mm = (LONG)m; nn = (LONG)n; if(!TakeMem()) return(_FALSE); printf("P2 NAME %s\n",symbols[NAME]); if(file[1]) fprintf(file[1],"P2 NAME %s\n",symbols[NAME]); /* A auf Schlupfvariablen vorbereiten */ iptr = list[ROWS_LIST]; for(count=0; iptr; iptr=iptr->next) { if((ch = *iptr->string) == 'L') SetM(A,n,iptr->nr,num_var+(++count),1.0); else if(ch == 'G') SetM(A,n,iptr->nr,num_var+(++count),-1.0); } /* COLUMNS-Sektion einlesen */ printf("P2 COLUMNS\n"); if(file[1]) fprintf(file[1],"P2 COLUMNS\n"); if(fseek(file[0],position[COLUMNS],0) == -1) { PrintError(errno,NULL); return(_FALSE); } do { if(!fgets(ptr[0],BUFFER-1,file[0])) { if(ferror(file[0])) { PrintError(errno,NULL); return(_FALSE); } } Cap(ptr[0],0,BUFFER); if(SearchExpr(ptr[0],&start[0],&stop[0])) { if(start[0] == 0) break; /* Abbruch von do{}while, Beginn neuer Sektion */ length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(!(iptr = SearchEl(buf[0],list[VAR_LIST],_FALSE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } j = iptr->nr; /* Spalte */ if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) && SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2]) ) { length = GetExpr(buf[1],ptr[1],start[1],stop[1]); length = GetExpr(buf[2],ptr[2],start[2],stop[2]); if(strcmp(symbols[GOAL],buf[1]) == 0) c[j-1] = minimize ? -atof(buf[2]) : atof(buf[2]); else { if(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL)) SetM(A,n,iptr->nr,j,atof(buf[2])); } if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) && SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4]) ) { length = GetExpr(buf[1],ptr[3],start[3],stop[3]); length = GetExpr(buf[2],ptr[4],start[4],stop[4]); if(strcmp(symbols[GOAL],buf[1]) == 0) c[j-1] = minimize ? -atof(buf[2]) : atof(buf[2]); else { if(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL)) SetM(A,n,iptr->nr,j,atof(buf[2])); } } } } } while(!feof(file[0])); /* RHS-Sektion einlesen */ if(symbflag & BIT_RHS && position[RHS]!=-1) { printf("P2 RHS %s\n",symbols[RHS]); if(file[1]) fprintf(file[1],"P2 RHS %s\n",symbols[RHS]); if(fseek(file[0],position[RHS],0) == -1) { PrintError(errno,NULL); return(_FALSE); } do { if(!fgets(ptr[0],BUFFER-1,file[0])) { if(ferror(file[0])) { PrintError(errno,NULL); return(_FALSE); } } Cap(ptr[0],0,BUFFER); if(SearchExpr(ptr[0],&start[0],&stop[0])) { if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */ length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(strcmp(symbols[RHS],buf[0]) == 0) { if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) && SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2]) ) { length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } i = iptr->nr; length = GetExpr(buf[2],ptr[2],start[2],stop[2]); b[i-1] = atof(buf[2]); if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) && SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4]) ) { length = GetExpr(buf[1],ptr[3],start[3],stop[3]); if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } i = iptr->nr; length = GetExpr(buf[2],ptr[4],start[4],stop[4]); b[i-1] = atof(buf[2]); } } } } } while(!feof(file[0])); } /* RANGES-Sektion einlesen */ if(symbflag & BIT_RANGES && num_lines!=0 && position[RANGES]!=-1) { printf("P2 RANGES %s\n",symbols[RANGES]); if(file[1]) fprintf(file[1],"P2 RANGES %s\n",symbols[RANGES]); if(fseek(file[0],position[RANGES],0) == -1) { PrintError(errno,NULL); return(_FALSE); } i = 0; /* Zähler für zusätzliche Zeilen */ do { if(!fgets(ptr[0],BUFFER-1,file[0])) { if(ferror(file[0])) { PrintError(errno,NULL); return(_FALSE); } } Cap(ptr[0],0,BUFFER); if(SearchExpr(ptr[0],&start[0],&stop[0])) { if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */ length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(strcmp(buf[0],symbols[RANGES]) == 0) { if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) && SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2]) ) { length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } if(++i > num_lines) { PrintError(ERR_FATAL,NULL); return(_FALSE); } ptr1 = A+(LONG)(iptr->nr-1)*nn; ptr2 = A+(LONG)(num_rows+i-1)*nn; CopyMemQuick(ptr1,ptr2,(LONG)((LONG)num_var*S_DOUBLE)); length = GetExpr(buf[2],ptr[2],start[2],stop[2]); if(*iptr->string == 'L') { SetM(A,n,num_rows+i,num_var+num_slack+i,-1.0); b[num_rows+i-1] = b[iptr->nr-1]-atof(buf[2]); } else { SetM(A,n,num_rows+i,num_var+num_slack+i,1.0); b[num_rows+i-1] = b[iptr->nr-1]+atof(buf[2]); } if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) && SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4]) ) { length = GetExpr(buf[1],ptr[3],start[3],stop[3]); if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } if(++i > num_lines) { PrintError(ERR_FATAL,NULL); return(_FALSE); } ptr1 = A+(LONG)(iptr->nr-1)*nn; ptr2 = A+(LONG)(num_rows+i-1)*nn; CopyMemQuick(ptr1,ptr2,(LONG)((LONG)num_var*S_DOUBLE)); length = GetExpr(buf[2],ptr[4],start[4],stop[4]); if(*iptr->string == 'L') { SetM(A,n,num_rows+i,num_var+num_slack+i,-1.0); b[num_rows+i-1] = b[iptr->nr-1]-atof(buf[2]); } else { SetM(A,n,num_rows+i,num_var+num_slack+i,1.0); b[num_rows+i-1] = b[iptr->nr-1]+atof(buf[2]); } } } } } } while(!feof(file[0])); } /* BOUNDS-Sektion einlesen */ if(symbflag & BIT_BOUNDS && position[BOUNDS]!=-1) { printf("P2 BOUNDS %s\n",symbols[BOUNDS]); if(file[1]) fprintf(file[1],"P2 BOUNDS %s\n",symbols[BOUNDS]); if(fseek(file[0],position[BOUNDS],0) == -1) { PrintError(errno,NULL); return(_FALSE); } do { if(!fgets(ptr[0],BUFFER-1,file[0])) { if(ferror(file[0])) { PrintError(errno,NULL); return(_FALSE); } } Cap(ptr[0],0,BUFFER); if(SearchExpr(ptr[0],&start[0],&stop[0])) { if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */ length = GetExpr(buf[0],ptr[0],start[0],stop[0]); if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) && SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2]) && SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) ) { length = GetExpr(buf[1],ptr[1],start[1],stop[1]); if(strcmp(buf[1],symbols[BOUNDS]) == 0) { length = GetExpr(buf[2],ptr[2],start[2],stop[2]); if(!(iptr = SearchEl(buf[2],list[VAR_LIST],_FALSE,NULL))) { PrintError(ERR_FATAL,NULL); return(_FALSE); } length = GetExpr(buf[3],ptr[3],start[3],stop[3]); if(buf[0][0] == 'U') upper[iptr->nr-1] = atof(buf[3]); else lower[iptr->nr-1] = atof(buf[3]); } } } } while(!feof(file[0])); } return(_TRUE); } /***************************************************************************** * BOOL CorrectBounds() -> _TRUE/_FALSE * * Anpassung des Gleichungssystems an lower == 0, Berechnung von c0start * * und rechte Seite b >= 0 machen. * * _TRUE : O.K. * * _FALSE : ERR_UP_LO * *****************************************************************************/ BOOL CorrectBounds() { REGISTER DOUBLE *ptr1, dummy; REGISTER SHORT j, i; BOOL found = _FALSE; VOID PrintError(); for(i=0; i upper[i]) { PrintError(ERR_UP_LO,NULL); return(_FALSE); } if(lower[i] != 0.0) found = _TRUE; if(upper[i] != INFINITE) upper[i] -= lower[i]; } if(found) { for(i=0; i _TRUE/_FALSE * * Sucht den ersten Ausdruck im String str und bestimmt die Position des * * ersten (start) und letzten (stop) Zeichens in str. * * _TRUE : O.K. * * _FALSE : kein Ausdruck gefunden * *****************************************************************************/ BOOL SearchExpr(str,start,stop) STRPTR str; SHORT *start, *stop; { TEXT ch; REGISTER SHORT pos1 = 0, pos2; /* Trennzeichen überspringen */ while((ch = str[pos1]) != '\0' && isspace(ch)) ++pos1; if(ch == '\0') return(_FALSE); /* Stringende erreicht, kein Ausdruck vorh. */ pos2 = pos1+1; while((ch = str[pos2]) != '\0' && !isspace(ch)) ++pos2; *start = pos1; *stop = pos2-1; return(_TRUE); } /***************************************************************************** * SHORT GetExpr(dest,ptr,start,stop) * * Kopiert den Ausdruck, der bei ptr+start beginnt und bei ptr+stop endet, * * nach dest. Danach werden alle Kleinbuchstaben zu Großbuchstaben. Das Er- * * gebnis ist die Länge des Ausdrucks * *****************************************************************************/ SHORT GetExpr(dest,ptr,start,stop) STRPTR dest, ptr; SHORT start, stop; { SHORT length, reallength; length = stop-start+1; reallength = length>BUFFER2-1 ? BUFFER2-1 : length; /* verhindert Überlauf */ strncpy(dest,ptr+start,reallength); dest[reallength] = '\0'; return(length); } /***************************************************************************** * VOID Cap(str,start,stop) * * String str in Großbuchstaben umwandeln (von start bis einschl. stop) * * Cap() bricht ab, falls stop oder das Stringende erreicht sind * *****************************************************************************/ VOID Cap(str,start,stop) STRPTR str; SHORT start, stop; { REGISTER SHORT pos; TEXT ch; for(pos = start; pos<=stop && (ch=str[pos])!='\0'; ++pos) { if(isalpha(ch) && islower(ch)) str[pos] = toupper(ch); } } /***************************************************************************** * ITEMPTR NewListEl(list,str) * * Fügt an die Liste list ein neues Element an (an den Anfang) und übergibt * * den neuen Listenanker. Falls dieser NULL ist, ERR_MEM. Außerdem wird der * * String str in das neue Listenelement kopiert * *****************************************************************************/ ITEMPTR NewListEl(list,str) ITEMPTR list; STRPTR str; { VOID PrintError(); ITEMPTR ptr; if(ptr = AllocMem(SIZE_ITEM,MEMF_CLEAR)) { ptr->next = list; strcpy(ptr->string,str); } else PrintError(ERR_MEM,NULL); return(ptr); } /***************************************************************************** * ITEMPTR SearchEl(str,list,spezial,chstr) * * Sucht den String str in der Liste list. Ist spezial==_TRUE, so wird erst * * ab dem zweiten Zeichen verglichen (für spezielles Format von ROWS_LIST). * * Wird bufstr != NULL angegeben, so wird das erste Zeichen des gefundenen * * Strings dort hineingeschrieben (Format für ROWS_LIST). * * Ergebnis ist entweder der Zeiger auf den gefundenen Eintrag, oder NULL, * * falls str nicht in der Liste enthalten ist * *****************************************************************************/ ITEMPTR SearchEl(str,list,spezial,chstr) STRPTR str; ITEMPTR list; BOOL spezial; STRPTR chstr; /* Zeiger auf Character */ { ITEMPTR ptr = list; STRPTR sptr; while(ptr) { sptr = spezial ? ptr->string+1 : ptr->string; if(strcmp(str,sptr)==0) { if(chstr) *chstr = *ptr->string; return(ptr); } ptr = ptr->next; } return(NULL); } /***************************************************************************** * VOID DeleteList(list) * * Löscht die Liste list. Vorsicht: list ist Zeiger auf Zeiger !! * *****************************************************************************/ VOID DeleteList(list) ITEMPTR *list; { if(*list) { DeleteList(&(*list)->next); FreeMem(*list,SIZE_ITEM); *list = NULL; } } /***************************************************************************** * VOID GetRidOfLists() * * Löscht alle Bezeichnerlisten * *****************************************************************************/ VOID GetRidOfLists() { SHORT i; VOID DeleteList(); for(i=0; i sys_nerr : eigene Fehlermeldungen * *****************************************************************************/ VOID PrintError(nr,str) INT nr; STRPTR str; { printf(":: Error %2d : ",nr); if(str) printf("(%s) ",str); if(nr<=sys_nerr) printf("%s\n",sys_errlist[nr]); else printf("%s\n",errors[nr-sys_nerr-1]); if(file[1]) { fprintf(file[1],":: Error %2d : ",nr); if(str) fprintf(file[1],"(%s) ",str); if(nr<=sys_nerr) fprintf(file[1],"%s\n",sys_errlist[nr]); else fprintf(file[1],"%s\n",errors[nr-sys_nerr-1]); } } /***************************************************************************** * INT GetInput(str) * * Liest eine Zeile von der Console (=stdin) in den String "str" ein * * Ergebnis: Fehlernummer bzw. 0, falls kein Fehler auftrat * *****************************************************************************/ INT GetInput(str) STRPTR str; { STRPTR gets(); if(!gets(str)) { if(feof(stdin)) return(ERR_EOF); /* nur, wenn stdin != Console ist */ else if(ferror(stdin)) return(errno); } return(0); } /***************************************************************************** * BOOL TakeMem() -> _TRUE/_FALSE * * TakeMem() alloziert den Speicher für die Felder. * * _TRUE : O.K. * * _FALSE : ERR_MEM * *****************************************************************************/ BOOL TakeMem() { LONG mem_needed, mem_avail, i; LONG AvailMem(); VOID GiveMemBack(), PrintError(); mem_needed = S_SHORT*(mm+2L*nn)+S_DOUBLE*(mm*(mm+nn+8L)+6L*nn); if(mem_needed > (mem_avail = AvailMem(NULL))) { sprintf(line,"%ld needed,%ld available",mem_needed,mem_avail); PrintError(ERR_MEM,line); return(_FALSE); } A = AllocMem(mm*nn*S_DOUBLE,MEMF_CLEAR); AB1 = AllocMem(mm*mm*S_DOUBLE,MEMF_CLEAR); b = AllocMem(mm*S_DOUBLE,MEMF_CLEAR); b2q = AllocMem(mm*S_DOUBLE,MEMF_CLEAR); c = AllocMem(nn*S_DOUBLE,MEMF_CLEAR); c2 = AllocMem((nn+mm)*S_DOUBLE,MEMF_CLEAR); upper = AllocMem((nn+mm)*S_DOUBLE,NULL); lower = AllocMem(nn*S_DOUBLE,MEMF_CLEAR); x = AllocMem((nn+mm)*S_DOUBLE,MEMF_CLEAR); cq = AllocMem(nn*S_DOUBLE,MEMF_CLEAR); pi = AllocMem(mm*S_DOUBLE,MEMF_CLEAR); dq = AllocMem(mm*S_DOUBLE,MEMF_CLEAR); help = AllocMem(mm*S_DOUBLE,MEMF_CLEAR); B = AllocMem(mm*S_SHORT,MEMF_CLEAR); Nq = AllocMem(nn*S_SHORT,MEMF_CLEAR); Nminus = AllocMem(nn*S_SHORT,MEMF_CLEAR); if(!(A && AB1 && b && b2q && c && c2 && upper && lower && x && cq && pi && dq && help && B && Nq && Nminus)) { GiveMemBack(); PrintError(ERR_MEM,NULL); return(_FALSE); } for(i=0; i<(nn+mm); ++i) upper[i] = INFINITE; return(_TRUE); } /***************************************************************************** * VOID GiveMemBack() * * Allozierten Speicher an das System zurückgeben. * *****************************************************************************/ VOID GiveMemBack() { if(A) FreeMem(A,mm*nn*S_DOUBLE); if(AB1) FreeMem(AB1,mm*mm*S_DOUBLE); if(b) FreeMem(b,mm*S_DOUBLE); if(b2q) FreeMem(b2q,mm*S_DOUBLE); if(c) FreeMem(c,nn*S_DOUBLE); if(c2) FreeMem(c2,(nn+mm)*S_DOUBLE); if(upper) FreeMem(upper,(nn+mm)*S_DOUBLE); if(lower) FreeMem(lower,nn*S_DOUBLE); if(x) FreeMem(x,(nn+mm)*S_DOUBLE); if(cq) FreeMem(cq,nn*S_DOUBLE); if(pi) FreeMem(pi,mm*S_DOUBLE); if(dq) FreeMem(dq,mm*S_DOUBLE); if(help) FreeMem(help,mm*S_DOUBLE); if(B) FreeMem(B,mm*S_SHORT); if(Nq) FreeMem(Nq,nn*S_SHORT); if(Nminus) FreeMem(Nminus,nn*S_SHORT); A = AB1 = b = b2q = c = c2 = upper = lower = x = cq = pi = dq = help = NULL; B = Nq = Nminus = NULL; }