home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Amiga / Applications / Mathematiques / ASimplex.lha / ASimplex / source / mpsx.c < prev    next >
C/C++ Source or Header  |  1989-09-16  |  48KB  |  1,556 lines

  1. /*****************************************************************************
  2.  * Modul  : mpsx.c                                                           *
  3.  * Zweck  : Einlesen eines files im MPSX-Standardeingabeformat               *
  4.  * Format : load <file> [-cGOAL] [-bRHS] [-rRANGES] [-uBOUNDS] [-m] [-fFILE] *
  5.  * Autor  : Stefan F÷rster                                                   *
  6.  *                                                                           *
  7.  * Datum      | Version | Bemerkung                                          *
  8.  * -----------|---------|--------------------------------------------------- *
  9.  * 05.03.1989 | 0.0     |                                                    *
  10.  * 07.03.1989 | 0.1     | PrintError()                                       *
  11.  * 08.03.1989 | 0.2     | Pass1()                                            *
  12.  * 09.03.1989 |         | Pass1() fertig                                     *
  13.  * 10.03.1989 | 0.3     | ZusΣtzliche Fehlermeldungen                        *
  14.  *            |         | SearchEl() liefert jetzt den Typ ITEMPTR           *
  15.  *            |         | ChooseSymbols(), Select()                          *
  16.  * 11.03.1989 | 0.4     | Pass2()                                            *
  17.  *            |         | Felder GLOBAL definiert                            *
  18.  * 13.03.1989 | 0.5     | Pass2() und CorrectBounds() fertig                 *
  19.  *            |         | BUG in ParseLine(): &stop[1] statt &stop[2]        *
  20.  *            |         | BUG in TakeMem(): AvailMem(NULL) statt AvailMem()  *
  21.  *            |         | BUG in ParseLine(): list[GOALS_LIST] durchsuchen   *
  22.  *            |         | BUG in MPSX(): ChooseSymbols() statt ChooseSymbols *
  23.  * 14.03.1989 | 1.0     | BUG in Pass2(): Wenn symbflag & BIT_RHS, ist       *
  24.  *            |         |                 list[RHS_LIST] leer (DeleteList()) *
  25.  *            |         | BUG in Pass2(): Fehler bei 2 Zielfkt. behoben      *
  26.  *            |         | BUG in Pass2(): RANGES: if(++i>num_lines) ...      *
  27.  *            |         | BUG in Pass2(): RANGES: num_rows+i statt m+i       *
  28.  *            |         | BUG in Pass2(): Schl.var.: Zeile iptr->nr statt i  *
  29.  *            |         | BUG in CorrectBounds(): upper[i] -= lower[i];      *
  30.  *            |         | 1. Testlauf erfolgreich                            *
  31.  * 17.03.1989 | 1.1     | zusΣtzlich min cTx m÷glich                         *
  32.  * 18.03.1989 | 1.2     | Optional Ausgabe an ein File m÷glich (-f)          *
  33.  * 06.05.1989 | 1.3     | MAXIMIZE/MINIMIZE wird angezeigt                   *
  34.  * 09.05.1989 | 1.3a    | Zeitmessung des Einlesevorgangs mittels PrintTime()*
  35.  * 20.05.1989 | 1.4     | Anpassung an neues Kommando "MINIMIZE"             *
  36.  * 21.07.1989 |         | Nach NAME ist jetzt ein Bezeichner mit max. 33     *
  37.  *            |         | Zeichen erlaubt.                                   *
  38.  * 06.08.1989 | 1.5     | Ausgabe von ROWS=,COLS=,NONZEROS=                  *
  39.  * 07.08.1989 |         | GetInput() neu formuliert wegen (NEW)CON:-window   *
  40.  *****************************************************************************/
  41.  
  42.  
  43. IMPORT STRPTR ctime(), fgets();
  44. IMPORT VOID   *AllocMem(), fclose(), SetM(), CopyMemQuick(), PrintTime();
  45. IMPORT FILE   *fopen();
  46. IMPORT INT    fseek();
  47. IMPORT LONG   ftell(), time();
  48.  
  49. GLOBAL DOUBLE  INFINITE;
  50. GLOBAL BOOL    minimize, global_minimize;
  51.  
  52. GLOBAL DOUBLE  c0start, c0;
  53. GLOBAL SHORT   m, n, *B, *Nq;
  54. GLOBAL DOUBLE  *A, *AB1, *b, *b2q, *c, *c2, *upper, *lower;
  55. GLOBAL DOUBLE  *x, *cq, *pi, *dq;
  56. GLOBAL SHORT   *Nminus;
  57. GLOBAL DOUBLE  *help;
  58.  
  59. GLOBAL TEXT    version[], comment[];
  60. GLOBAL FILE    *con;
  61. GLOBAL STRPTR  errors[];
  62.  
  63.  
  64. USHORT      symbflag;
  65. GLOBAL TEXT symbols[NUM_SYMBOLS][MAX_STRLEN+1];
  66. TEXT        filename[MAX_FILELEN+1];
  67. GLOBAL FILE *file[2];
  68. struct stat file_stat;
  69.  
  70. GLOBAL ITEMPTR list[NUM_LISTS];
  71. LONG        position[NUM_SYMBOLS];
  72.  
  73. SHORT       num_var, num_slack, num_rows, num_lines, num_goals, num_rhs;
  74. SHORT       num_ranges, num_bounds;
  75. LONG        nonzeros;
  76.  
  77. LONG        mm, nn;
  78.  
  79. TEXT        line_nr[9];         /* ZΣhlvariable, max 99999999 (8 Zeichen) */
  80. TEXT        line[BUFFER];       /* eingelesene Zeile */
  81. TEXT        buf[4][BUFFER2+1];  /* Zwischenspeicher */
  82.  
  83.  
  84.  
  85.  
  86. /*****************************************************************************
  87.  * BOOL MPSX() -> _TRUE/_FALSE                                               *
  88.  * Hauptprogramm von MPSX.c                                                  *
  89.  *                                                                           *
  90.  * Input:  args   : Zeiger auf Argument-String (hinter load)                 *
  91.  *                                                                           *
  92.  * Output: _FALSE : Fehler beim Einlesen                                     *
  93.  *         _TRUE  : c0start: Korrekturwert fⁿr den Zielfunktionswert         *
  94.  *                  m,n: m und n                                             *
  95.  *                  Zeiger auf A,AB1,etc.                                    *
  96.  *****************************************************************************/
  97.  
  98. BOOL    MPSX(args)
  99.  
  100. STRPTR  args;
  101.  
  102. {
  103.   SHORT i;
  104.   ULONG    sec1, sec2, micro1, micro2;
  105.   BOOL  GetArgs(), Pass1(), Pass2(), ChooseSymbols(), CorrectBounds();
  106.   VOID  GetRidOfLists(), GiveMemBack();
  107.  
  108.   CurrentTime(&sec1,µ1);
  109.  
  110.   num_var = num_goals = num_rhs = num_ranges = num_bounds = 0;
  111.   num_slack = num_rows = num_lines = 0;
  112.  
  113.   GetRidOfLists();
  114.  
  115.   for(i=0; i<NUM_SYMBOLS; ++i) position[i] = -1L;
  116.  
  117.   if(!GetArgs(args)) return(_FALSE);
  118.  
  119.   if(!Pass1() || !ChooseSymbols() || !Pass2() || !CorrectBounds()) {
  120.     GetRidOfLists();
  121.     GiveMemBack();
  122.     return(_FALSE);
  123.   }
  124.  
  125.   CurrentTime(&sec2,µ2);
  126.   PrintTime("-> Read time = ",sec1,micro1,sec2,micro2,file[1]);
  127.   puts("");
  128.   if(file[1]) fputs("",file[1]);
  129.  
  130.   return(_TRUE);
  131. }
  132.  
  133.  
  134.  
  135. /*****************************************************************************
  136.  * BOOL GetArgs() -> _TRUE/_FALSE                                            *
  137.  * wertet den Argument-String hinter load aus und setzt symbflag und         *
  138.  * symbols[][] entsprechend                                                  *
  139.  * _TRUE  : O.K. (file wurde ge÷ffnet)                                       *
  140.  * _FALSE : Fehler aufgetreten                                               *
  141.  *****************************************************************************/
  142.  
  143. BOOL    GetArgs(str)
  144.  
  145. STRPTR  str;
  146.  
  147. {
  148.   SHORT   start, stop, length;
  149.   LONG    t;
  150.   TEXT    ch;
  151.   VOID    PrintError(), Cap();
  152.   BOOL    SearchExpr();
  153.   SHORT   GetExpr();
  154.   STRPTR  ptr;
  155.  
  156.   symbflag = 0;
  157.  
  158.   if(!SearchExpr(str,&start,&stop)) {
  159.     PrintError(ERR_INVALID_ARGS,NULL);
  160.     return(_FALSE);
  161.   }
  162.   else {   /* file-Name gefunden */
  163.     length = GetExpr(filename,str,start,stop);
  164.     if(length > MAX_FILELEN) {
  165.       PrintError(ERR_FILE_TOO_LONG,filename);
  166.       return(_FALSE);
  167.     }
  168.     else { /* und hat korrekte LΣnge */
  169.       if(!(file[0] = fopen(filename,"r"))) {
  170.         PrintError(errno,filename);
  171.         PrintError(ERR_NOT_READ,filename);
  172.         return(_FALSE);
  173.       }
  174.     }
  175.   }
  176.  
  177.   /* Jetzt die Argumente */
  178.  
  179.   ptr = str+stop+1;
  180.   minimize = global_minimize;
  181.  
  182.   while(SearchExpr(ptr,&start,&stop)) {
  183.  
  184.     Cap(ptr,start,stop);
  185.  
  186.     if((length = stop-start-1)==0 && strncmp(ptr+start,"-M",2)==0)
  187.       minimize = !global_minimize;
  188.  
  189.     else if(length > 0 && strncmp(ptr+start,"-F",2) == 0) {
  190.       length = GetExpr(buf[0],ptr,start+2,stop);        
  191.       if(length > MAX_FILELEN) {
  192.         PrintError(ERR_FILE_TOO_LONG,buf[0]);
  193.         return(_FALSE);
  194.       }
  195.       if(!(file[1] = fopen(buf[0],"w"))) {
  196.         PrintError(errno,buf[0]);
  197.         PrintError(ERR_NOT_WRITE,buf[0]);
  198.         return(_FALSE);
  199.       }
  200.       fprintf(file[1],"%s\n%s\n\n",version+20,comment);
  201.       t = time(NULL);
  202.       fprintf(file[1],"Hardcopy on %s\n",ctime(&t));
  203.     }
  204.  
  205.     else {
  206.  
  207.       if(length <= 0) goto invalid; /* (stop-start+1)-2 */
  208.  
  209.       if(length > MAX_STRLEN) {
  210.         *(ptr+stop+1) = '\0';
  211.         PrintError(ERR_NAME_TOO_LONG,ptr+start+2);
  212.         return(_FALSE);
  213.       }
  214.  
  215.       if(strncmp(ptr+start,"-C",2) == 0) {
  216.         if(symbflag & BIT_GOAL) goto invalid; /* zwei Zielfkt. angegeben */
  217.         else {
  218.           symbflag |= BIT_GOAL;
  219.           strncpy(symbols[GOAL],ptr+start+2,length);
  220.           symbols[GOAL][length] = '\0';
  221.         }
  222.       }
  223.       else if(strncmp(ptr+start,"-B",2) == 0) {
  224.         if(symbflag & BIT_RHS) goto invalid;
  225.         else {
  226.           symbflag |= BIT_RHS;
  227.           strncpy(symbols[RHS],ptr+start+2,length);
  228.           symbols[RHS][length] = '\0';
  229.         }
  230.       }
  231.       else if(strncmp(ptr+start,"-R",2) == 0) {
  232.         if(symbflag & BIT_RANGES) goto invalid;
  233.         else {
  234.           symbflag |= BIT_RANGES;
  235.           strncpy(symbols[RANGES],ptr+start+2,length);
  236.           symbols[RANGES][length] = '\0';
  237.         }
  238.       }
  239.       else if(strncmp(ptr+start,"-U",2) == 0) {
  240.         if(symbflag & BIT_BOUNDS) goto invalid;
  241.         else {
  242.           symbflag |= BIT_BOUNDS;
  243.           strncpy(symbols[BOUNDS],ptr+start+2,length);
  244.           symbols[BOUNDS][length] = '\0';
  245.         }
  246.       }
  247.       else goto invalid;
  248.     }
  249.  
  250.     ptr += stop+1;
  251.  
  252.   } /* while() */
  253.  
  254.  
  255.   if(stat(filename,&file_stat) == -1) {
  256.     PrintError(errno,filename);
  257.     return(_FALSE);
  258.   }
  259.   else {
  260.     printf("== loading %s %ld bytes\n",filename,file_stat.st_size);
  261.     printf("   %s",ctime(&file_stat.st_mtime));
  262.   }
  263.  
  264.   return(_TRUE);
  265.  
  266. invalid: /* Sprungmarke (na ja) fⁿr "invalid arguments" */
  267.   PrintError(ERR_INVALID_ARGS,NULL);
  268.   return(_FALSE);
  269. }
  270.  
  271.  
  272.  
  273. /*****************************************************************************
  274.  * BOOL Pass1() -> _TRUE/_FALSE                                              *
  275.  * Pass1() durchlΣuft <file> zum ersten Mal. Es werden Listen der Variablen, *
  276.  * der rechten Seiten (falls noch nicht festgelegt) usw. angelegt. Au▀erdem  *
  277.  * erfolgt eine Syntaxⁿberprⁿfung.                                           *
  278.  * _TRUE  : OK                                                               *
  279.  * _FALSE : Fehler aufgetreten                                               *
  280.  *****************************************************************************/
  281.  
  282. BOOL Pass1()
  283.  
  284. {
  285.   LONG    count = 0, pos;
  286.   SHORT   start[5], stop[5], length;
  287.   USHORT  found = 0, actual = 0;
  288.   TEXT    ch;
  289.   STRPTR  ptr[5];
  290.   ITEMPTR iptr;
  291.   BOOL    SearchExpr(), ParseLine();
  292.   VOID    PrintError(), UpdateLine();
  293.   SHORT   GetExpr();
  294.   ITEMPTR NewListEl(), SearchEl();
  295.  
  296.   printf("P1 0");
  297.   sprintf(line_nr,"%ld",count);
  298.  
  299.   ptr[0] = line;
  300.  
  301.   /* 1. Sektion mu▀ "NAME" sein */
  302.  
  303.   do {
  304.     if(!fgets(ptr[0],BUFFER-1,file[0])) {
  305.       if(feof(file[0])) goto finish;
  306.       if(ferror(file[0])) {
  307.         puts("");
  308.         PrintError(errno,NULL);
  309.         return(_FALSE);
  310.       }
  311.     }
  312.     UpdateLine(&count);
  313.     pos = ftell(file[0]);
  314.     Cap(ptr[0],0,BUFFER);
  315.   } while(!SearchExpr(ptr[0],&start[0],&stop[0]));
  316.   length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  317.  
  318.   if(start[0] != 0) {
  319.     puts("");
  320.     PrintError(ERR_SECTIONS,buf[0]);
  321.     PrintError(ERR_NO_NAME,buf[0]);
  322.     return(_FALSE);
  323.   }
  324.  
  325.   if(length != 4 || strncmp(buf[0],"NAME",4) != 0) {
  326.     puts("");
  327.     PrintError(ERR_NO_NAME,buf[0]);
  328.     return(_FALSE);
  329.   }
  330.  
  331.   if(!SearchExpr((ptr[1]=ptr[0]+stop[0]+1),&start[1],&stop[1])) {
  332.     puts("");
  333.     PrintError(ERR_NO_NAME,NULL);
  334.     return(_FALSE);
  335.   }
  336.   length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  337.  
  338.   if(length > 33) {
  339.     puts("");
  340.     PrintError(ERR_NAME_TOO_LONG,buf[1]);
  341.     return(_FALSE);
  342.   }
  343.  
  344.   symbflag |= BIT_NAME;
  345.   found |= BIT_NAME;
  346.   strcpy(symbols[NAME],buf[1]);
  347.   position[NAME] = pos;
  348.  
  349.  
  350.   /* Jetzt folgen die anderen Sektionen */
  351.  
  352.   FOREVER {
  353.  
  354.     if(feof(file[0])) goto finish;
  355.  
  356.     if(!fgets(ptr[0],BUFFER-1,file[0])) {
  357.       if(ferror(file[0])) {
  358.         puts("");
  359.         PrintError(errno,NULL);
  360.         return(_FALSE);
  361.       }
  362.     }
  363.     UpdateLine(&count);
  364.     pos = ftell(file[0]);
  365.     Cap(ptr[0],0,BUFFER);
  366.  
  367.     if(!SearchExpr(ptr[0],&start[0],&stop[0])) continue; /* FOREVER */
  368.     length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  369.     if(length > MAX_STRLEN) {
  370.       puts("");
  371.       PrintError(ERR_NAME_TOO_LONG,buf[0]);
  372.       return(_FALSE);
  373.     }
  374.  
  375.     if(start[0] == 0) {  /* Start einer neuen Sektion */
  376.  
  377.       if(length==6 && strncmp(buf[0],"ENDATA",6) == 0) {
  378.         found |= BIT_ENDATA;
  379.         goto finish;
  380.       }
  381.       else if(length==4 && strncmp(buf[0],"ROWS",4) == 0) {
  382.         if(found & BIT_ROWS) {
  383.           puts("");
  384.           PrintError(ERR_2SECTIONS,buf[0]);
  385.           return(_FALSE);
  386.         }
  387.         else {
  388.           found |= BIT_ROWS;
  389.           actual = BIT_ROWS;
  390.           position[ROWS] = pos;
  391.           continue;
  392.         }
  393.       }
  394.       else if(length==7 && strncmp(buf[0],"COLUMNS",7) == 0) {
  395.         if(found & BIT_COLUMNS) {
  396.           puts("");
  397.           PrintError(ERR_2SECTIONS,buf[0]);
  398.           return(_FALSE);
  399.         }
  400.         else {
  401.           found |= BIT_COLUMNS;
  402.           actual = BIT_COLUMNS;
  403.           position[COLUMNS] = pos;
  404.           continue;
  405.         }
  406.       }
  407.       else if(length==3 && strncmp(buf[0],"RHS",3) == 0) {
  408.         if(found & BIT_RHS) {
  409.           puts("");
  410.           PrintError(ERR_2SECTIONS,buf[0]);
  411.           return(_FALSE);
  412.         }
  413.         else {
  414.           found |= BIT_RHS;
  415.           actual = BIT_RHS;
  416.           position[RHS] = pos;
  417.           continue;
  418.         }
  419.       }
  420.       else if(length==6 && strncmp(buf[0],"RANGES",6) == 0) {
  421.         if(found & BIT_RANGES) {
  422.           puts("");
  423.           PrintError(ERR_2SECTIONS,buf[0]);
  424.           return(_FALSE);
  425.         }
  426.         else {
  427.           found |= BIT_RANGES;
  428.           actual = BIT_RANGES;
  429.           position[RANGES] = pos;
  430.           continue;
  431.         }
  432.       }
  433.       else if(length==6 && strncmp(buf[0],"BOUNDS",6) == 0) {
  434.         if(found & BIT_BOUNDS) {
  435.           puts("");
  436.           PrintError(ERR_2SECTIONS,buf[0]);
  437.           return(_FALSE);
  438.         }
  439.         else {
  440.           found |= BIT_BOUNDS;
  441.           actual = BIT_BOUNDS;
  442.           position[BOUNDS] = pos;
  443.           continue;
  444.         }
  445.       }
  446.       else {
  447.         puts("");
  448.         PrintError(ERR_UNKNOWN_SEC,buf[0]);
  449.         return(_FALSE);
  450.       }
  451.  
  452.     }  /* if(start[0]==0) */
  453.  
  454.     else {  /* if(start[0]!=0) */
  455.  
  456.       if(actual == 0) {
  457.         puts("");
  458.         PrintError(ERR_SECTIONS,buf[0]);
  459.         return(_FALSE);
  460.       }
  461.  
  462.       switch(actual) {
  463.  
  464.         case BIT_ROWS:
  465.           if(length!=1 || (ch = buf[0][0])!='N' && ch!='E' && ch!='L' && 
  466.              ch!='G') {
  467.             puts("");
  468.             PrintError(ERR_INV_ROWS_TYPE,buf[0]);
  469.             return(_FALSE);
  470.           }
  471.           ptr[1] = ptr[0]+start[0]+1;
  472.           if(!SearchExpr(ptr[1],&start[1],&stop[1])) {
  473.             puts("");
  474.             PrintError(ERR_MISSING,NULL);
  475.             return(_FALSE);
  476.           }
  477.           length = GetExpr(buf[0]+1,ptr[1],start[1],stop[1]);
  478.           if(length > MAX_STRLEN) {
  479.             puts("");
  480.             PrintError(ERR_NAME_TOO_LONG,buf[0]+1);
  481.             return(_FALSE);
  482.           }
  483.           if(ch == 'N') {  /* Zielfunktion */
  484.             if(SearchEl(buf[0]+1,list[GOALS_LIST],_FALSE,NULL)) {
  485.               puts("");
  486.               PrintError(ERR_DOUBLE,buf[0]+1);
  487.               return(_FALSE);
  488.             }
  489.             if(!(iptr = NewListEl(list[GOALS_LIST],buf[0]+1))) return(_FALSE);
  490.             else {
  491.               if(list[GOALS_LIST]) iptr->nr = list[GOALS_LIST]->nr+1;
  492.               else                 iptr->nr = 1;
  493.               list[GOALS_LIST] = iptr;
  494.               ++num_goals;
  495.             }
  496.           }
  497.           else {   /* Typ L, G oder E */
  498.             if(SearchEl(buf[0]+1,list[ROWS_LIST],_TRUE,NULL)) {
  499.               puts("");
  500.               PrintError(ERR_DOUBLE,buf[0]+1);
  501.               return(_FALSE);
  502.             }
  503.             if(!(iptr = NewListEl(list[ROWS_LIST],buf[0]))) return(_FALSE);
  504.             else {
  505.               if(list[ROWS_LIST]) iptr->nr = list[ROWS_LIST]->nr+1;
  506.               else                iptr->nr = 1;
  507.               list[ROWS_LIST] = iptr;
  508.               ++num_rows;
  509.               if(ch == 'L' || ch == 'G') ++num_slack;
  510.             }
  511.           }
  512.           break;
  513.  
  514.         case BIT_COLUMNS:
  515.           if(!ParseLine(VAR_LIST,buf[0],stop[0])) return(_FALSE);
  516.           break;
  517.  
  518.         case BIT_RHS:
  519.           if(!ParseLine(RHS_LIST,buf[0],stop[0])) return(_FALSE);
  520.           break;
  521.  
  522.         case BIT_RANGES:
  523.           if(!ParseLine(RANGES_LIST,buf[0],stop[0])) return(_FALSE);
  524.           break;
  525.  
  526.         case BIT_BOUNDS:
  527.           if(length!=2 || (strncmp(buf[0],"UP",2)!=0 &&
  528.              strncmp(buf[0],"LO",2)!=0)) {
  529.             puts("");
  530.             PrintError(ERR_INV_BOUNDS_TYPE,buf[0]);
  531.             return(_FALSE);
  532.           }
  533.           /* Jetzt mⁿssen drei Ausdrⁿcke folgen */
  534.           if(!SearchExpr((ptr[1]=ptr[0]+stop[0]+1),&start[1],&stop[1]) ||
  535.              !SearchExpr((ptr[2]=ptr[1]+stop[1]+1),&start[2],&stop[2]) ||
  536.              !SearchExpr((ptr[3]=ptr[2]+stop[2]+1),&start[3],&stop[3])   ) {
  537.             puts("");
  538.             PrintError(ERR_MISSING,NULL);
  539.             return(_FALSE);
  540.           }
  541.           length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  542.           if(length > MAX_STRLEN) {
  543.             puts("");
  544.             PrintError(ERR_NAME_TOO_LONG,buf[1]);
  545.             return(_FALSE);
  546.           }
  547.           if(!SearchEl(buf[1],list[BOUNDS_LIST],_FALSE,NULL)) {
  548.             if(!(iptr = NewListEl(list[BOUNDS_LIST],buf[1]))) return(_FALSE);
  549.             else {
  550.               if(list[BOUNDS_LIST]) iptr->nr = list[BOUNDS_LIST]->nr+1;
  551.               else                  iptr->nr = 1;
  552.               list[BOUNDS_LIST] = iptr;
  553.               ++num_bounds;
  554.             }
  555.           }
  556.           length = GetExpr(buf[2],ptr[2],start[2],stop[2]);
  557.           if(length > MAX_STRLEN) {
  558.             puts("");
  559.             PrintError(ERR_NAME_TOO_LONG,buf[2]);
  560.             return(_FALSE);
  561.           }
  562.           if(!SearchEl(buf[2],list[VAR_LIST],_FALSE,NULL)) {
  563.             puts("");
  564.             PrintError(ERR_UNKNOWN_ID,buf[2]);
  565.             return(_FALSE);
  566.           }
  567.           break;
  568.  
  569.       } /* switch(actual) */
  570.     } /* else if(start[0]!=0) */
  571.   } /* FOREVER() */
  572.  
  573.  
  574. finish:  /* Sprungmarke, falls feof(file[0]) oder ENDATA erreicht */
  575.   if(!(found & BIT_ROWS) || num_rows == 0) {
  576.     puts("");
  577.     PrintError(ERR_NO_ROWS,NULL);
  578.     return(_FALSE);
  579.   }
  580.   if(!(found & BIT_COLUMNS) || num_var == 0) {
  581.     puts("");
  582.     PrintError(ERR_NO_COLUMNS,NULL);
  583.     return(_FALSE);
  584.   }
  585.   if(!(found & BIT_RHS)) {
  586.     puts("");
  587.     PrintError(ERR_NO_RHS,NULL);
  588.     return(_FALSE);
  589.   }
  590.   if(!(found & BIT_ENDATA)) {
  591.     puts("");
  592.     PrintError(ERR_NO_ENDATA,NULL);
  593.     return(_FALSE);
  594.   }
  595.   if(position[NAME] >= position[ROWS] ||
  596.      position[ROWS] >= position[COLUMNS] ||
  597.      position[COLUMNS] >= position[RHS] ||
  598.      position[RANGES] != -1 && position[BOUNDS] != -1 &&
  599.      position[RANGES] >= position[BOUNDS]                ) {
  600.     puts("");
  601.     PrintError(ERR_ORDER,NULL);
  602.     return(_FALSE);
  603.   }
  604.  
  605.   puts("");
  606.   return(_TRUE);  /* alle FehlerfΣlle ⁿberstanden */
  607. }
  608.  
  609.  
  610.  
  611. /*****************************************************************************
  612.  * VOID UpdateLine()                                                         *
  613.  * Aktualisiert den ZeilenzΣhler von Pass1()                                 *
  614.  *****************************************************************************/
  615.  
  616. VOID UpdateLine(c)
  617.  
  618. LONG *c;
  619.  
  620. {
  621.   SHORT i, len = strlen(line_nr);
  622.  
  623.   for(i=0; i<len; ++i) printf("%c",8);
  624.   sprintf(line_nr,"%ld",++(*c));
  625.   printf("%s",line_nr);
  626. }
  627.  
  628.  
  629.  
  630. /*****************************************************************************
  631.  * BOOL ParseLine(list_type,bufptr,end0) -> _TRUE/_FALSE                     *
  632.  * ▄berprⁿft eine Zeile (aus der Sektion COLUMNS, RHS oder RANGES) auf       *
  633.  * korrekte Syntax. bufptr ist Zeiger auf den Puffer, der den ersten Aus-    *
  634.  * druck der Zeile enthΣlt. Falls dieser noch nicht in der jeweiligen Liste  *
  635.  * enthalten ist, wird er angefⁿgt. list_type kann die Werte VAR_LIST,       *
  636.  * RHS_LIST oder RANGES_LIST annehmen. end0 ist stop[0] von Pass1()          *
  637.  * _TRUE  : O.K.                                                             *
  638.  * _FALSE : Fehler aufgetreten                                               *
  639.  *****************************************************************************/
  640.  
  641. BOOL    ParseLine(list_type,bufptr,end0)
  642.  
  643. SHORT   list_type;
  644. STRPTR  bufptr;
  645. SHORT   end0;
  646.  
  647. {
  648.   SHORT   start[5], stop[5], length;
  649.   TEXT    ch;
  650.   STRPTR  ptr[5];
  651.   ITEMPTR iptr, dptr;
  652.   ITEMPTR NewListEl(), SearchEl();
  653.  
  654.  
  655.   ptr[0] = line; /* wie auch in Pass1() */
  656.  
  657.   if(!(dptr = SearchEl(bufptr,list[list_type],_FALSE,NULL))) { /* neue Var. */
  658.     if(!(iptr = NewListEl(list[list_type],bufptr))) return(_FALSE);
  659.     else {
  660.       if(list[list_type]) iptr->nr = list[list_type]->nr+1;
  661.       else                iptr->nr = 1;
  662.       if(list_type == RANGES_LIST) iptr->anz = 0;
  663.       list[list_type] = iptr;
  664.       switch(list_type) {
  665.         case VAR_LIST:    ++num_var;
  666.                           break;
  667.         case RHS_LIST:    ++num_rhs;
  668.                           break;
  669.         case RANGES_LIST: ++num_ranges;
  670.                           break;
  671.       }
  672.       dptr = iptr;
  673.     }
  674.   }
  675.   /* dptr zeigt jetzt auf den 1.Eintrag der Zeile */
  676.   ptr[1] = ptr[0]+end0+1; /* mind. 2 Ausdrⁿcke in dieser Zeile */
  677.   if(!SearchExpr(ptr[1],&start[1],&stop[1]) ||
  678.      !SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2])) {
  679.     puts("");
  680.     PrintError(ERR_MISSING,NULL);
  681.     return(_FALSE);
  682.   }
  683.   length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  684.   if(length > MAX_STRLEN) {
  685.     puts("");
  686.     PrintError(ERR_NAME_TOO_LONG,buf[1]);
  687.     return(_FALSE);
  688.   }
  689.   ch = '\0';
  690.   if(!SearchEl(buf[1],list[ROWS_LIST],_TRUE,&ch) &&
  691.      !SearchEl(buf[1],list[GOALS_LIST],_FALSE,NULL) ) {
  692.     puts("");
  693.     PrintError(ERR_UNKNOWN_ID,buf[1]);
  694.     return(_FALSE);
  695.   }
  696.   if(list_type == RANGES_LIST && ch == 'E') {
  697.     puts("");
  698.     PrintError(ERR_INV_RANGES,buf[1]);
  699.     return(_FALSE);
  700.   }
  701.   if(list_type == RANGES_LIST) ++dptr->anz;
  702.   ptr[3] = ptr[2]+stop[2]+1; /* noch mehr (genau 2) ? */
  703.   if(SearchExpr(ptr[3],&start[3],&stop[3])) {
  704.     ptr[4] = ptr[3]+stop[3]+1;
  705.     if(!SearchExpr(ptr[4],&start[4],&stop[4])) {
  706.       puts("");
  707.       PrintError(ERR_MISSING,NULL);
  708.       return(_FALSE);
  709.     }
  710.     else {
  711.       length = GetExpr(buf[3],ptr[3],start[3],stop[3]);
  712.       if(length > MAX_STRLEN) {
  713.         puts("");
  714.         PrintError(ERR_NAME_TOO_LONG,buf[3]);
  715.         return(_FALSE);
  716.       }
  717.       ch = '\0';
  718.       if(!SearchEl(buf[3],list[ROWS_LIST],_TRUE,&ch) &&
  719.          !SearchEl(buf[3],list[GOALS_LIST],_FALSE,NULL) ) {
  720.         puts("");
  721.         PrintError(ERR_UNKNOWN_ID,buf[3]);
  722.         return(_FALSE);
  723.       }
  724.       if(list_type == RANGES_LIST && ch == 'E') {
  725.         puts("");
  726.         PrintError(ERR_INV_RANGES,buf[1]);
  727.         return(_FALSE);
  728.       }
  729.       if(list_type == RANGES_LIST) ++dptr->anz;
  730.     }
  731.   }
  732.  
  733.   return(_TRUE);
  734. }
  735.  
  736.  
  737.  
  738. /*****************************************************************************
  739.  * BOOL ChooseSymbols() -> _TRUE/_FALSE                                      *
  740.  * Legt endgⁿltig die Bezeichner der Zielfunktion, der rechten Seite, des    *
  741.  * Bereichs und der Grenzen fest. Au▀erdem wird num_lines ermittelt.         *
  742.  * _TRUE  : O.K.                                                             *
  743.  * _FALSE : Fehler aufgetreten                                               *
  744.  *****************************************************************************/
  745.  
  746. BOOL ChooseSymbols()
  747.  
  748. {
  749.   ITEMPTR dptr;
  750.   ITEMPTR Select(), SearchEl();
  751.   VOID    DeleteList();
  752.  
  753.  
  754.   if(!(symbflag & BIT_GOAL)) {
  755.     if(num_goals == 0) {
  756.       PrintError(ERR_NO_GOAL,NULL);
  757.       return(_FALSE);
  758.     }
  759.     else if(num_goals == 1) {
  760.       strcpy(symbols[GOAL],list[GOALS_LIST]->string);
  761.       symbflag |= BIT_GOAL;
  762.     }
  763.     else {
  764.       if(!(dptr = Select(list[GOALS_LIST],"Possible goals"))) return(_FALSE);
  765.       else {
  766.         strcpy(symbols[GOAL],dptr->string);
  767.         symbflag |= BIT_GOAL;
  768.       }
  769.     }
  770.   }
  771.   else if(!SearchEl(symbols[GOAL],list[GOALS_LIST],_FALSE,NULL)) {
  772.     PrintError(ERR_NO_GOAL,NULL);
  773.     return(_FALSE);
  774.   }
  775.   DeleteList(&list[GOALS_LIST]);
  776.  
  777.   /* Ist Zielfunktion schon als normale Zeile deklariert ? */
  778.   if(SearchEl(symbols[GOAL],list[ROWS_LIST],_TRUE,NULL)) {
  779.     PrintError(ERR_DOUBLE,symbols[GOAL]);
  780.     return(_FALSE);
  781.   }
  782.  
  783.   if(!(symbflag & BIT_RHS) && num_rhs>0) {
  784.     if(num_rhs == 1) {
  785.       strcpy(symbols[RHS],list[RHS_LIST]->string);
  786.       symbflag |= BIT_RHS;
  787.     }
  788.     else {
  789.       if(!(dptr = Select(list[RHS_LIST],"Possible right hand sides")))
  790.         return(_FALSE);
  791.       else {
  792.         strcpy(symbols[RHS],dptr->string);
  793.         symbflag |= BIT_RHS;
  794.       }
  795.     }
  796.   }
  797.   DeleteList(&list[RHS_LIST]);
  798.  
  799.   if(symbflag & BIT_RANGES) {
  800.     if(dptr = SearchEl(symbols[RANGES],list[RANGES_LIST],_FALSE,NULL))
  801.          num_lines = dptr->anz;
  802.     else num_lines = 0;
  803.   }
  804.   else {
  805.     if(num_ranges == 0) num_lines = 0;
  806.     else if(num_ranges == 1) {
  807.       strcpy(symbols[RANGES],list[RANGES_LIST]->string);
  808.       symbflag |= BIT_RANGES;
  809.       num_lines = list[RANGES_LIST]->anz;
  810.     }
  811.     else {
  812.       if(!(dptr = Select(list[RANGES_LIST],"Possible ranges"))) return(_FALSE);
  813.       else {
  814.         strcpy(symbols[RANGES],dptr->string);
  815.         symbflag |= BIT_RANGES;
  816.         num_lines = dptr->anz;
  817.       }
  818.     }
  819.   }
  820.   DeleteList(&list[RANGES_LIST]);
  821.  
  822.   if(!(symbflag & BIT_BOUNDS) && num_bounds>0) {
  823.     if(num_bounds == 1) {
  824.       strcpy(symbols[BOUNDS],list[BOUNDS_LIST]->string);
  825.       symbflag |= BIT_BOUNDS;
  826.     }
  827.     else {
  828.       if(!(dptr = Select(list[BOUNDS_LIST],"Possible bounds")))
  829.         return(_FALSE);
  830.       else {
  831.         strcpy(symbols[BOUNDS],dptr->string);
  832.         symbflag |= BIT_BOUNDS;
  833.       }
  834.     }
  835.   }
  836.   DeleteList(&list[BOUNDS_LIST]);
  837.  
  838.   return(_TRUE);
  839.  
  840. }
  841.  
  842.  
  843.  
  844. /*****************************************************************************
  845.  * ITEMPTR Select(lptr,str)                                                  *
  846.  * Auswahl eines Eintrags der Liste lptr durch den Benutzer.                 *
  847.  * Ergebnis ist der Zeiger auf den gewΣhlten Eintrag, NULL, falls ein Fehler *
  848.  * aufgetreten ist.  lptr != NULL wird angenommen. Zu Beginn wird der String *
  849.  * str ausgegeben.                                                           *
  850.  *****************************************************************************/
  851.  
  852. ITEMPTR Select(lptr,str)
  853.  
  854. ITEMPTR lptr;
  855. STRPTR  str;
  856.  
  857. {
  858.   ITEMPTR ptr = lptr;
  859.   SHORT   count = 0, atoi(), choice, i;
  860.   VOID    GetInput();
  861.  
  862.   printf("?? %s:\n",str);
  863.  
  864.   while(ptr) {
  865.     printf("   %-8s  %3d\n",ptr->string,++count);
  866.     ptr = ptr->next;
  867.   }
  868.  
  869.   do {
  870.     printf("?? Your choice : ");
  871.     GetInput(line);
  872.   } while((choice = atoi(line)) <= 0 || choice > count);
  873.  
  874.   ptr = lptr;
  875.   for(i=1; i<choice; ++i) ptr = ptr->next;
  876.  
  877.   return(ptr);
  878. }
  879.  
  880.  
  881.  
  882. /*****************************************************************************
  883.  * BOOL Pass2() -> _TRUE/_FALSE                                              *
  884.  * Pass2() stellt den Speicherplatz bereit und liest die Daten in die er-    *
  885.  * zeugten Felder ein.                                                       *
  886.  * _TRUE  : O.K.                                                             *
  887.  * _FALSE : Fehler aufgetreten                                               *
  888.  *****************************************************************************/
  889.  
  890. BOOL Pass2()
  891.  
  892. {
  893.   TEXT    ch;
  894.   SHORT   i, j, count, start[5], stop[5], length;
  895.   STRPTR  ptr[5];
  896.   ITEMPTR iptr;
  897.   DOUBLE  *ptr1, *ptr2, value;
  898.   ITEMPTR SearchEl();
  899.   SHORT   GetExpr();
  900.   BOOL    TakeMem(), SearchExpr();
  901.   VOID    Cap();
  902.   DOUBLE  atof();
  903.  
  904.  
  905.   ptr[0] = line;
  906.  
  907.   m = num_rows+num_lines;
  908.   n = num_var+num_slack+num_lines;
  909.  
  910.   mm = (LONG)m;
  911.   nn = (LONG)n;
  912.  
  913.   if(!TakeMem()) return(_FALSE);
  914.  
  915.   printf("P2 NAME    %s %s\n",symbols[NAME],minimize ? "MINIMIZE" : "MAXIMIZE");
  916.   if(file[1])
  917.     fprintf(file[1],"P2 NAME    %s %s\n",symbols[NAME],minimize ? "MINIMIZE" :
  918.                                                                   "MAXIMIZE"  );
  919.  
  920.   /* A auf Schlupfvariablen vorbereiten */
  921.  
  922.   iptr = list[ROWS_LIST];
  923.   for(count=0; iptr; iptr=iptr->next) {
  924.     if((ch = *iptr->string) == 'L') SetM(A,n,iptr->nr,num_var+(++count),1.0);
  925.     else if(ch == 'G')              SetM(A,n,iptr->nr,num_var+(++count),-1.0);
  926.   }
  927.  
  928.   /* COLUMNS-Sektion einlesen */
  929.  
  930.   nonzeros = 0L;
  931.  
  932.   printf("P2 COLUMNS\n");
  933.   if(file[1]) fprintf(file[1],"P2 COLUMNS\n");
  934.   if(fseek(file[0],position[COLUMNS],0) == -1) {
  935.     PrintError(errno,NULL);
  936.     return(_FALSE);
  937.   }
  938.  
  939.   do {
  940.     if(!fgets(ptr[0],BUFFER-1,file[0])) {
  941.       if(ferror(file[0])) {
  942.         PrintError(errno,NULL);
  943.         return(_FALSE);
  944.       }
  945.     }
  946.     Cap(ptr[0],0,BUFFER);
  947.  
  948.     if(SearchExpr(ptr[0],&start[0],&stop[0])) {
  949.  
  950.       if(start[0] == 0) break; /* Abbruch von do{}while, Beginn neuer Sektion */
  951.       length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  952.       if(!(iptr = SearchEl(buf[0],list[VAR_LIST],_FALSE,NULL))) {
  953.         PrintError(ERR_FATAL,NULL);
  954.         return(_FALSE);
  955.       }
  956.       j = iptr->nr;  /* Spalte */
  957.  
  958.       if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) &&
  959.          SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2])    ) {
  960.         length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  961.         length = GetExpr(buf[2],ptr[2],start[2],stop[2]);
  962.         if(strcmp(symbols[GOAL],buf[1]) == 0) {
  963.           if(value = minimize ? -atof(buf[2]) : atof(buf[2])) {
  964.             ++nonzeros;
  965.             c[j-1] = value;
  966.           }
  967.         }
  968.         else {
  969.           if(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL)) {
  970.             if(value=atof(buf[2])) {
  971.               ++nonzeros;
  972.               SetM(A,n,iptr->nr,j,value);
  973.             }
  974.           }
  975.         }
  976.  
  977.         if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) &&
  978.           SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4])    ) {
  979.           length = GetExpr(buf[1],ptr[3],start[3],stop[3]);
  980.           length = GetExpr(buf[2],ptr[4],start[4],stop[4]);
  981.           if(strcmp(symbols[GOAL],buf[1]) == 0) {
  982.             if(value = minimize ? -atof(buf[2]) : atof(buf[2])) {
  983.               ++nonzeros;
  984.               c[j-1] = value;
  985.             }
  986.           }
  987.           else {
  988.             if(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL)) {
  989.               if(value=atof(buf[2])) {
  990.                 ++nonzeros;
  991.                 SetM(A,n,iptr->nr,j,value);
  992.               }
  993.             }
  994.           }
  995.         }
  996.       }
  997.     }
  998.  
  999.   } while(!feof(file[0]));
  1000.  
  1001.  
  1002.   /* RHS-Sektion einlesen */
  1003.  
  1004.   if(symbflag & BIT_RHS && position[RHS]!=-1) {
  1005.  
  1006.     printf("P2 RHS     %s\n",symbols[RHS]);
  1007.     if(file[1]) fprintf(file[1],"P2 RHS     %s\n",symbols[RHS]);
  1008.  
  1009.     if(fseek(file[0],position[RHS],0) == -1) {
  1010.       PrintError(errno,NULL);
  1011.       return(_FALSE);
  1012.     }
  1013.  
  1014.     do {
  1015.       if(!fgets(ptr[0],BUFFER-1,file[0])) {
  1016.         if(ferror(file[0])) {
  1017.           PrintError(errno,NULL);
  1018.           return(_FALSE);
  1019.         }
  1020.       }
  1021.       Cap(ptr[0],0,BUFFER);
  1022.  
  1023.       if(SearchExpr(ptr[0],&start[0],&stop[0])) {
  1024.  
  1025.         if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */
  1026.         length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  1027.         if(strcmp(symbols[RHS],buf[0]) == 0) {
  1028.           if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) &&
  1029.              SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2])    ) {
  1030.             length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  1031.             if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) {
  1032.               PrintError(ERR_FATAL,NULL);
  1033.               return(_FALSE);
  1034.             }
  1035.             i = iptr->nr;
  1036.             length = GetExpr(buf[2],ptr[2],start[2],stop[2]);
  1037.             b[i-1] = atof(buf[2]);
  1038.  
  1039.             if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) &&
  1040.                SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4])    ) {
  1041.               length = GetExpr(buf[1],ptr[3],start[3],stop[3]);
  1042.               if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) {
  1043.                 PrintError(ERR_FATAL,NULL);
  1044.                 return(_FALSE);
  1045.               }
  1046.               i = iptr->nr;
  1047.               length = GetExpr(buf[2],ptr[4],start[4],stop[4]);
  1048.               b[i-1] = atof(buf[2]);
  1049.             }
  1050.           }
  1051.         }
  1052.       }
  1053.     } while(!feof(file[0]));
  1054.   }
  1055.  
  1056.  
  1057.   /* RANGES-Sektion einlesen */
  1058.  
  1059.   if(symbflag & BIT_RANGES && num_lines!=0 && position[RANGES]!=-1) {
  1060.  
  1061.     printf("P2 RANGES  %s\n",symbols[RANGES]);
  1062.     if(file[1]) fprintf(file[1],"P2 RANGES  %s\n",symbols[RANGES]);
  1063.  
  1064.     if(fseek(file[0],position[RANGES],0) == -1) {
  1065.       PrintError(errno,NULL);
  1066.       return(_FALSE);
  1067.     }
  1068.  
  1069.     i = 0;  /* ZΣhler fⁿr zusΣtzliche Zeilen */
  1070.     do {
  1071.       if(!fgets(ptr[0],BUFFER-1,file[0])) {
  1072.         if(ferror(file[0])) {
  1073.           PrintError(errno,NULL);
  1074.           return(_FALSE);
  1075.         }
  1076.       }
  1077.       Cap(ptr[0],0,BUFFER);
  1078.  
  1079.       if(SearchExpr(ptr[0],&start[0],&stop[0])) {
  1080.  
  1081.         if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */
  1082.         length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  1083.  
  1084.         if(strcmp(buf[0],symbols[RANGES]) == 0) {
  1085.  
  1086.           if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) &&
  1087.              SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2])   ) {
  1088.             length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  1089.             if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) {
  1090.               PrintError(ERR_FATAL,NULL);
  1091.               return(_FALSE);
  1092.             }
  1093.             if(++i > num_lines) {
  1094.               PrintError(ERR_FATAL,NULL);
  1095.               return(_FALSE);
  1096.             }
  1097.             ptr1 = A+(LONG)(iptr->nr-1)*nn;
  1098.             ptr2 = A+(LONG)(num_rows+i-1)*nn;
  1099.             CopyMemQuick(ptr1,ptr2,(LONG)((LONG)num_var*S_DOUBLE));
  1100.             length = GetExpr(buf[2],ptr[2],start[2],stop[2]);
  1101.             if(*iptr->string == 'L') {
  1102.               SetM(A,n,num_rows+i,num_var+num_slack+i,-1.0);
  1103.               b[num_rows+i-1] = b[iptr->nr-1]-atof(buf[2]);
  1104.             }
  1105.             else {
  1106.               SetM(A,n,num_rows+i,num_var+num_slack+i,1.0);
  1107.               b[num_rows+i-1] = b[iptr->nr-1]+atof(buf[2]);
  1108.             }
  1109.  
  1110.             if(SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3]) &&
  1111.               SearchExpr((ptr[4] = ptr[3]+stop[3]+1),&start[4],&stop[4])   ) {
  1112.               length = GetExpr(buf[1],ptr[3],start[3],stop[3]);
  1113.               if(!(iptr = SearchEl(buf[1],list[ROWS_LIST],_TRUE,NULL))) {
  1114.                 PrintError(ERR_FATAL,NULL);
  1115.                 return(_FALSE);
  1116.               }
  1117.               if(++i > num_lines) {
  1118.                 PrintError(ERR_FATAL,NULL);
  1119.                 return(_FALSE);
  1120.               }
  1121.               ptr1 = A+(LONG)(iptr->nr-1)*nn;
  1122.               ptr2 = A+(LONG)(num_rows+i-1)*nn;
  1123.               CopyMemQuick(ptr1,ptr2,(LONG)((LONG)num_var*S_DOUBLE));
  1124.               length = GetExpr(buf[2],ptr[4],start[4],stop[4]);
  1125.               if(*iptr->string == 'L') {
  1126.                 SetM(A,n,num_rows+i,num_var+num_slack+i,-1.0);
  1127.                 b[num_rows+i-1] = b[iptr->nr-1]-atof(buf[2]);
  1128.               }
  1129.               else {
  1130.                 SetM(A,n,num_rows+i,num_var+num_slack+i,1.0);
  1131.                 b[num_rows+i-1] = b[iptr->nr-1]+atof(buf[2]);
  1132.               }
  1133.             }
  1134.           }
  1135.         }
  1136.       }
  1137.     } while(!feof(file[0]));
  1138.   }
  1139.  
  1140.  
  1141.   /* BOUNDS-Sektion einlesen */
  1142.  
  1143.   if(symbflag & BIT_BOUNDS && position[BOUNDS]!=-1) {
  1144.  
  1145.     printf("P2 BOUNDS  %s\n",symbols[BOUNDS]);
  1146.     if(file[1]) fprintf(file[1],"P2 BOUNDS  %s\n",symbols[BOUNDS]);
  1147.  
  1148.     if(fseek(file[0],position[BOUNDS],0) == -1) {
  1149.       PrintError(errno,NULL);
  1150.       return(_FALSE);
  1151.     }
  1152.  
  1153.     do {
  1154.       if(!fgets(ptr[0],BUFFER-1,file[0])) {
  1155.         if(ferror(file[0])) {
  1156.           PrintError(errno,NULL);
  1157.           return(_FALSE);
  1158.         }
  1159.       }
  1160.       Cap(ptr[0],0,BUFFER);
  1161.  
  1162.       if(SearchExpr(ptr[0],&start[0],&stop[0])) {
  1163.  
  1164.         if(start[0] == 0) break; /* Abbruch von do{}while, neue Sektion */
  1165.         length = GetExpr(buf[0],ptr[0],start[0],stop[0]);
  1166.  
  1167.         if(SearchExpr((ptr[1] = ptr[0]+stop[0]+1),&start[1],&stop[1]) &&
  1168.            SearchExpr((ptr[2] = ptr[1]+stop[1]+1),&start[2],&stop[2]) &&
  1169.            SearchExpr((ptr[3] = ptr[2]+stop[2]+1),&start[3],&stop[3])   ) {
  1170.           length = GetExpr(buf[1],ptr[1],start[1],stop[1]);
  1171.           if(strcmp(buf[1],symbols[BOUNDS]) == 0) {
  1172.             length = GetExpr(buf[2],ptr[2],start[2],stop[2]);
  1173.             if(!(iptr = SearchEl(buf[2],list[VAR_LIST],_FALSE,NULL))) {
  1174.               PrintError(ERR_FATAL,NULL);
  1175.               return(_FALSE);
  1176.             }
  1177.             length = GetExpr(buf[3],ptr[3],start[3],stop[3]);
  1178.             if(buf[0][0] == 'U') upper[iptr->nr-1] = atof(buf[3]);
  1179.             else                 lower[iptr->nr-1] = atof(buf[3]);
  1180.           }
  1181.         }
  1182.       }
  1183.     } while(!feof(file[0]));
  1184.   }
  1185.  
  1186.   printf("++ ROWS     = %d\n",num_rows+1);
  1187.   printf("++ COLS     = %d\n",num_var);
  1188.   printf("++ NONZEROS = %ld\n",nonzeros);
  1189.   if(file[1]) {
  1190.     fprintf(file[1],"++ ROWS     = %d\n",num_rows+1);
  1191.     fprintf(file[1],"++ COLS     = %d\n",num_var);
  1192.     fprintf(file[1],"++ NONZEROS = %ld\n",nonzeros);
  1193.   }
  1194.  
  1195.   return(_TRUE);
  1196. }
  1197.  
  1198.  
  1199.  
  1200. /*****************************************************************************
  1201.  * BOOL CorrectBounds() -> _TRUE/_FALSE                                      *
  1202.  * Anpassung des Gleichungssystems an lower == 0, Berechnung von c0start     *
  1203.  * und rechte Seite b >= 0 machen.                                           *
  1204.  * _TRUE  : O.K.                                                             *
  1205.  * _FALSE : ERR_UP_LO                                                        *
  1206.  *****************************************************************************/
  1207.  
  1208. BOOL CorrectBounds()
  1209.  
  1210. {
  1211.   REGISTER DOUBLE *ptr1, dummy;
  1212.   REGISTER SHORT  j, i;
  1213.   BOOL            found = _FALSE;
  1214.   VOID            PrintError();
  1215.  
  1216.   for(i=0; i<num_var; ++i) {
  1217.     if(upper[i] != INFINITE && lower[i] > upper[i]) {
  1218.       PrintError(ERR_UP_LO,NULL);
  1219.       return(_FALSE);
  1220.     }
  1221.     if(lower[i] != 0.0) found = _TRUE;
  1222.     if(upper[i] != INFINITE)  upper[i] -= lower[i];
  1223.   }
  1224.  
  1225.   if(found) {
  1226.     for(i=0; i<m; ++i) {
  1227.       ptr1 = A+(LONG)i*nn;
  1228.       for(dummy=0.0,j=0; j<num_var; ++j) dummy += (*ptr1++)*lower[j];
  1229.       b[i] -= dummy;
  1230.     }
  1231.     for(c0start=0.0,j=0; j<num_var; ++j) c0start += c[j]*lower[j];
  1232.   }
  1233.   else c0start = 0.0;
  1234.  
  1235.   for(i=0; i<m; ++i) {
  1236.     if(b[i] < 0.0) {
  1237.       ptr1 = A+(LONG)i*nn;
  1238.       for(j=0; j<n; ++j) *ptr1++ *= -1.0;
  1239.       b[i] *= -1.0;
  1240.     }
  1241.   }
  1242.  
  1243.  
  1244.   return(_TRUE);
  1245. }
  1246.  
  1247.  
  1248.  
  1249. /*****************************************************************************
  1250.  * BOOL SearchExpr(str,start,stop) -> _TRUE/_FALSE                           *
  1251.  * Sucht den ersten Ausdruck im String str und bestimmt die Position des     *
  1252.  * ersten (start) und letzten (stop) Zeichens in str.                        *
  1253.  * _TRUE  : O.K.                                                             *
  1254.  * _FALSE : kein Ausdruck gefunden                                           *
  1255.  *****************************************************************************/
  1256.  
  1257. BOOL    SearchExpr(str,start,stop)
  1258.  
  1259. STRPTR  str;
  1260. SHORT   *start, *stop;
  1261.  
  1262. {
  1263.   TEXT            ch;
  1264.   REGISTER SHORT  pos1 = 0, pos2;
  1265.  
  1266.   /* Trennzeichen ⁿberspringen */
  1267.   while((ch = str[pos1]) != '\0' && isspace(ch)) ++pos1;
  1268.  
  1269.   if(ch == '\0') return(_FALSE); /* Stringende erreicht, kein Ausdruck vorh. */
  1270.  
  1271.   pos2 = pos1+1;
  1272.   while((ch = str[pos2]) != '\0' && !isspace(ch)) ++pos2;
  1273.  
  1274.   *start = pos1;
  1275.   *stop = pos2-1;
  1276.   return(_TRUE);
  1277. }
  1278.  
  1279.  
  1280.  
  1281. /*****************************************************************************
  1282.  * SHORT GetExpr(dest,ptr,start,stop)                                        *
  1283.  * Kopiert den Ausdruck, der bei ptr+start beginnt und bei ptr+stop endet,   *
  1284.  * nach dest. Danach werden alle Kleinbuchstaben zu Gro▀buchstaben. Das Er-  *
  1285.  * gebnis ist die LΣnge des Ausdrucks                                        *
  1286.  *****************************************************************************/
  1287.  
  1288. SHORT   GetExpr(dest,ptr,start,stop)
  1289.  
  1290. STRPTR  dest, ptr;
  1291. SHORT   start, stop;
  1292.  
  1293. {
  1294.   SHORT length, reallength;
  1295.  
  1296.   length = stop-start+1;
  1297.   reallength = length>BUFFER2-1 ? BUFFER2-1 : length; /* verhindert ▄berlauf */
  1298.   strncpy(dest,ptr+start,reallength);
  1299.   dest[reallength] = '\0';
  1300.   return(length);
  1301. }
  1302.  
  1303.  
  1304.  
  1305. /*****************************************************************************
  1306.  * VOID Cap(str,start,stop)                                                  *
  1307.  * String str in Gro▀buchstaben umwandeln (von start bis einschl. stop)      *
  1308.  * Cap() bricht ab, falls stop oder das Stringende erreicht sind             *
  1309.  *****************************************************************************/
  1310.  
  1311. VOID    Cap(str,start,stop)
  1312.  
  1313. STRPTR  str;
  1314. SHORT   start, stop;
  1315.  
  1316. {
  1317.   REGISTER SHORT pos;
  1318.   TEXT           ch;
  1319.  
  1320.   for(pos = start; pos<=stop && (ch=str[pos])!='\0'; ++pos) {
  1321.     if(isalpha(ch) && islower(ch)) str[pos] = toupper(ch);
  1322.   }
  1323. }
  1324.  
  1325.  
  1326.  
  1327. /*****************************************************************************
  1328.  * ITEMPTR NewListEl(list,str)                                               *
  1329.  * Fⁿgt an die Liste list ein neues Element an (an den Anfang) und ⁿbergibt  *
  1330.  * den neuen Listenanker. Falls dieser NULL ist, ERR_MEM. Au▀erdem wird der  *
  1331.  * String str in das neue Listenelement kopiert                              *
  1332.  *****************************************************************************/
  1333.  
  1334. ITEMPTR NewListEl(list,str)
  1335.  
  1336. ITEMPTR list;
  1337. STRPTR  str;
  1338.  
  1339. {
  1340.   VOID    PrintError();
  1341.   ITEMPTR ptr;
  1342.  
  1343.   if(ptr = AllocMem(SIZE_ITEM,MEMF_CLEAR)) {
  1344.     ptr->next = list;
  1345.     strcpy(ptr->string,str);
  1346.   }
  1347.   else PrintError(ERR_MEM,NULL);
  1348.  
  1349.   return(ptr);
  1350. }
  1351.  
  1352.  
  1353.  
  1354. /*****************************************************************************
  1355.  * ITEMPTR SearchEl(str,list,spezial,chstr)                                  *
  1356.  * Sucht den String str in der Liste list. Ist spezial==_TRUE, so wird erst  *
  1357.  * ab dem zweiten Zeichen verglichen (fⁿr spezielles Format von ROWS_LIST).  *
  1358.  * Wird bufstr != NULL angegeben, so wird das erste Zeichen des gefundenen   *
  1359.  * Strings dort hineingeschrieben (Format fⁿr ROWS_LIST).                    *
  1360.  * Ergebnis ist entweder der Zeiger auf den gefundenen Eintrag, oder NULL,   *
  1361.  * falls str nicht in der Liste enthalten ist                                *
  1362.  *****************************************************************************/
  1363.  
  1364. ITEMPTR SearchEl(str,list,spezial,chstr)
  1365.  
  1366. STRPTR  str;
  1367. ITEMPTR list;
  1368. BOOL    spezial;
  1369. STRPTR  chstr;    /* Zeiger auf Character */
  1370.  
  1371. {
  1372.   ITEMPTR ptr = list;
  1373.   STRPTR  sptr;
  1374.  
  1375.   while(ptr) {
  1376.     sptr = spezial ? ptr->string+1 : ptr->string;
  1377.     if(strcmp(str,sptr)==0) {
  1378.       if(chstr) *chstr = *ptr->string;
  1379.       return(ptr);
  1380.     }
  1381.     ptr = ptr->next;
  1382.   }
  1383.  
  1384.   return(NULL);
  1385. }
  1386.  
  1387.  
  1388.  
  1389. /*****************************************************************************
  1390.  * VOID DeleteList(list)                                                     *
  1391.  * L÷scht die Liste list. Vorsicht: list ist Zeiger auf Zeiger !!            *
  1392.  *****************************************************************************/
  1393.  
  1394. VOID    DeleteList(list)
  1395.  
  1396. ITEMPTR *list;
  1397.  
  1398. {
  1399.   if(*list) {
  1400.     DeleteList(&(*list)->next);
  1401.     FreeMem(*list,SIZE_ITEM);
  1402.     *list = NULL;
  1403.   }
  1404. }
  1405.  
  1406.  
  1407.  
  1408. /*****************************************************************************
  1409.  * VOID GetRidOfLists()                                                      *
  1410.  * L÷scht alle Bezeichnerlisten                                              *
  1411.  *****************************************************************************/
  1412.  
  1413. VOID GetRidOfLists()
  1414.  
  1415. {
  1416.   SHORT i;
  1417.   VOID  DeleteList();
  1418.  
  1419.   for(i=0; i<NUM_LISTS; ++i) DeleteList(&list[i]);
  1420. }
  1421.  
  1422.  
  1423.  
  1424. /*****************************************************************************
  1425.  * VOID PrintError(nr,str)                                                   *
  1426.  * Gibt die Fehlermeldung zur Fehlernummer nr aus, optional davor einen      *
  1427.  * String str.
  1428.  * 0 <= nr <= sys_nerr : vorgegebene Systemfehlermeldungen                   *
  1429.  * nr > sys_nerr       : eigene Fehlermeldungen                              *
  1430.  *****************************************************************************/
  1431.  
  1432. VOID    PrintError(nr,str)
  1433. INT     nr;
  1434. STRPTR  str;
  1435.  
  1436. {
  1437.   printf(":: Error %2d : ",nr);
  1438.   if(str) printf("(%s) ",str);
  1439.   if(nr<=sys_nerr) printf("%s\n",sys_errlist[nr]);
  1440.   else             printf("%s\n",errors[nr-sys_nerr-1]);
  1441.  
  1442.   if(file[1]) {
  1443.     fprintf(file[1],":: Error %2d : ",nr);
  1444.     if(str) fprintf(file[1],"(%s) ",str);
  1445.     if(nr<=sys_nerr) fprintf(file[1],"%s\n",sys_errlist[nr]);
  1446.     else             fprintf(file[1],"%s\n",errors[nr-sys_nerr-1]);
  1447.   }
  1448. }
  1449.  
  1450.  
  1451.  
  1452. /*****************************************************************************
  1453.  * VOID GetInput(str)                                                        *
  1454.  * Liest eine Zeile von der Console (=con) in den String "str" ein           *
  1455.  * Ergebnis: Fehlernummer bzw. 0, falls kein Fehler auftrat                  *
  1456.  *****************************************************************************/
  1457.  
  1458. VOID    GetInput(str)
  1459. STRPTR  str;
  1460. {
  1461.   TEXT  getc(), ch;
  1462.   SHORT pos = 0;
  1463.  
  1464.   rewind(con);
  1465.   while((ch = getc(con))!='\n' && ch!='\r' && ch!=EOF) str[pos++] = ch;
  1466.   str[pos] = '\0';
  1467.   rewind(con);
  1468. }
  1469.  
  1470.  
  1471.  
  1472. /*****************************************************************************
  1473.  * BOOL TakeMem() -> _TRUE/_FALSE                                            *
  1474.  * TakeMem() alloziert den Speicher fⁿr die Felder.                          *
  1475.  * _TRUE  : O.K.                                                             *
  1476.  * _FALSE : ERR_MEM                                                          *
  1477.  *****************************************************************************/
  1478.  
  1479. BOOL TakeMem()
  1480.  
  1481. {
  1482.   LONG  mem_needed, mem_avail, i;
  1483.   LONG  AvailMem();
  1484.   VOID  GiveMemBack(), PrintError();
  1485.  
  1486.   mem_needed = S_SHORT*(mm+2L*nn)+S_DOUBLE*(mm*(mm+nn+8L)+6L*nn);
  1487.  
  1488.   if(mem_needed > (mem_avail = AvailMem(NULL))) {
  1489.     sprintf(line,"%ld needed,%ld available",mem_needed,mem_avail);
  1490.     PrintError(ERR_MEM,line);
  1491.     return(_FALSE);
  1492.   }
  1493.  
  1494.   A       = AllocMem(mm*nn*S_DOUBLE,MEMF_CLEAR);
  1495.   AB1     = AllocMem(mm*mm*S_DOUBLE,MEMF_CLEAR);
  1496.   b       = AllocMem(mm*S_DOUBLE,MEMF_CLEAR);
  1497.   b2q     = AllocMem(mm*S_DOUBLE,MEMF_CLEAR);
  1498.   c       = AllocMem(nn*S_DOUBLE,MEMF_CLEAR);
  1499.   c2      = AllocMem((nn+mm)*S_DOUBLE,MEMF_CLEAR);
  1500.   upper   = AllocMem((nn+mm)*S_DOUBLE,NULL);
  1501.   lower   = AllocMem(nn*S_DOUBLE,MEMF_CLEAR);
  1502.   x       = AllocMem((nn+mm)*S_DOUBLE,MEMF_CLEAR);
  1503.   cq      = AllocMem(nn*S_DOUBLE,MEMF_CLEAR);
  1504.   pi      = AllocMem(mm*S_DOUBLE,MEMF_CLEAR);
  1505.   dq      = AllocMem(mm*S_DOUBLE,MEMF_CLEAR);
  1506.   help    = AllocMem(mm*S_DOUBLE,MEMF_CLEAR);
  1507.  
  1508.   B       = AllocMem(mm*S_SHORT,MEMF_CLEAR);
  1509.   Nq      = AllocMem(nn*S_SHORT,MEMF_CLEAR);
  1510.   Nminus  = AllocMem(nn*S_SHORT,MEMF_CLEAR);
  1511.  
  1512.   if(!(A && AB1 && b && b2q && c && c2 && upper && lower && x && cq && pi &&
  1513.        dq && help && B && Nq && Nminus)) {
  1514.     GiveMemBack();
  1515.     PrintError(ERR_MEM,NULL);
  1516.     return(_FALSE);
  1517.   }
  1518.  
  1519.   for(i=0; i<(nn+mm); ++i) upper[i] = INFINITE;
  1520.  
  1521.   return(_TRUE);
  1522. }
  1523.  
  1524.  
  1525.  
  1526. /*****************************************************************************
  1527.  * VOID GiveMemBack()                                                        *
  1528.  * Allozierten Speicher an das System zurⁿckgeben.                           *
  1529.  *****************************************************************************/
  1530.  
  1531. VOID GiveMemBack()
  1532.  
  1533. {
  1534.   if(A)       FreeMem(A,mm*nn*S_DOUBLE);
  1535.   if(AB1)     FreeMem(AB1,mm*mm*S_DOUBLE);
  1536.   if(b)       FreeMem(b,mm*S_DOUBLE);
  1537.   if(b2q)     FreeMem(b2q,mm*S_DOUBLE);
  1538.   if(c)       FreeMem(c,nn*S_DOUBLE);
  1539.   if(c2)      FreeMem(c2,(nn+mm)*S_DOUBLE);
  1540.   if(upper)   FreeMem(upper,(nn+mm)*S_DOUBLE);
  1541.   if(lower)   FreeMem(lower,nn*S_DOUBLE);
  1542.   if(x)       FreeMem(x,(nn+mm)*S_DOUBLE);
  1543.   if(cq)      FreeMem(cq,nn*S_DOUBLE);
  1544.   if(pi)      FreeMem(pi,mm*S_DOUBLE);
  1545.   if(dq)      FreeMem(dq,mm*S_DOUBLE);
  1546.   if(help)    FreeMem(help,mm*S_DOUBLE);
  1547.  
  1548.   if(B)       FreeMem(B,mm*S_SHORT);
  1549.   if(Nq)      FreeMem(Nq,nn*S_SHORT);
  1550.   if(Nminus)  FreeMem(Nminus,nn*S_SHORT);
  1551.  
  1552.   A = AB1 = b = b2q = c = c2 = upper = lower = x = cq = pi = dq = help = NULL;
  1553.  
  1554.   B = Nq = Nminus = NULL;
  1555. }
  1556.