home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / pstoedit.zip / source.zip / pstoedit.2.50 / src / drvbase.cpp < prev    next >
C/C++ Source or Header  |  1996-11-22  |  18KB  |  659 lines

  1. /* 
  2.    drvbase.cpp : This file is part of pstoedit
  3.    Basic, driver independent output routines
  4.  
  5.    Copyright (C) 1993,1994,1995,1996 Wolfgang Glunz, Wolfgang.Glunz@zfe.siemens.de
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. #include <stdlib.h>
  24. #include <iostream.h>
  25. #include <string.h>
  26. #if !defined(unix) && !defined(__unix__) && !defined(__unix)
  27. #include <strstrea.h>
  28. #else
  29. #include <strstream.h>
  30. #endif
  31. #include "drvbase.h"
  32.  
  33. drvbase::drvbase(const char * driveroptions_p,ostream & theoutStream, 
  34.          ostream & theerrStream,
  35.          bool backendSupportsSubPathes_p,
  36.          bool backendSupportsCurveto_p, 
  37.          bool backendSupportsMerging_p) 
  38.         : // constructor
  39.     backendSupportsSubPathes(backendSupportsSubPathes_p),
  40.     backendSupportsCurveto(backendSupportsCurveto_p),
  41.     backendSupportsMerging(backendSupportsMerging_p),
  42.  
  43.     d_argc        (0),
  44.     d_argv        (0),
  45.     page_empty          (1),
  46.     outf                (theoutStream),
  47.     errf                (theerrStream),
  48.     scale               (1.0f),
  49.     // set some common defaults
  50.     currentDeviceHeight (792.0f * scale),
  51.     x_offset            (0.0f),
  52.     y_offset            (0.0f),
  53.     currentPageNumber   (0),
  54.     pathnumber        (0),
  55.     verbose            (false),
  56.     domerge            (false),
  57.     driveroptions    (0)
  58.     // init segment info for first segment
  59.     // all others will be updated with each newsegment
  60.     verbose = (getenv("PSTOEDITVERBOSE") != 0);
  61.     if (verbose) { 
  62.     errf << "verbose mode turned on\n" << endl;
  63.     }
  64.     numbers = new float[maxpoints]; // The number stack
  65.     nextFreeNumber = 0;
  66.  
  67.  
  68.     // preparse driveroptions and build d_argc and d_argv
  69.     if (driveroptions_p) {
  70.         driveroptions = strdup(driveroptions_p);
  71.  
  72.     istrstream optstream(driveroptions,strlen(driveroptions));
  73.     const long startOfStream = optstream.tellg();
  74.     char currentarg[100];
  75.         // first cound number of arguments
  76.         while(!optstream.eof()) {
  77.         optstream.width(sizeof(currentarg));
  78.         optstream >> currentarg;
  79.         d_argc++;
  80.     }
  81.     d_argv = new const char *[d_argc+1];
  82.     // now fill d_args array;
  83.     optstream.seekg(startOfStream); // reposition to start
  84.     optstream.clear();
  85.     d_argc=0;
  86.         while(!optstream.eof()) {
  87.         optstream >> currentarg;
  88.         d_argv[d_argc] = strdup(currentarg);
  89.         d_argc++;
  90.     }
  91.     d_argv[d_argc] = 0;
  92.         if (verbose) { 
  93.         errf << "got " << d_argc << " driver arguments" << endl;
  94.         for (unsigned int i = 0; i < d_argc ; i++ ) {
  95.             errf << "Driver option " << i << ":" << d_argv[i] << endl;
  96.         }
  97.     }
  98.     }
  99.  
  100.     currentPath = &p1;
  101.     lastPath    = &p2;
  102.     outputPath  = currentPath;
  103.     
  104.     if ((numbers == 0) || (p1.path == 0) || (p2.path == 0) ) {
  105.     errf << "new failed in drvbase::drvbase " << endl;
  106.     exit(1);
  107.     }
  108.  
  109.     setCurrentFontName("Courier",1);
  110.     setCurrentFontFamilyName("Courier");
  111.     setCurrentFontWeight("Regular");
  112.     setCurrentFontFullName("Courier");
  113.     setCurrentFontSize(10.0f);
  114. }
  115.  
  116. drvbase::~drvbase() { 
  117.     delete [] numbers;
  118.     currentPath = 0;
  119.     lastPath    = 0;
  120.     outputPath  = 0;
  121.     for (unsigned int i = 0; i < d_argc ; i++ ) {
  122.         free((char *)d_argv[i]); // use free because of strdup uses malloc
  123.     }
  124.     delete [] d_argv;
  125.     if (driveroptions) {
  126.         free((char *) driveroptions);
  127.     }
  128.     yylexcleanup();
  129. }
  130.  
  131. void drvbase::run(bool merge)
  132. {
  133.     domerge = false; // default
  134.     if (merge) {
  135.         if ( backendSupportsMerging ) {
  136.             domerge = true;
  137.         } else {
  138.             errf << "the selected backend does not support merging, -merge ignored" << endl;
  139.         }
  140.     }
  141.     yylex();
  142.     outputPath->clear(); // define past the end path as empty
  143.     dumpPath(); // dump last path 
  144.     // close page (if no explicit showpage was done)
  145.     if (!page_empty) {
  146.         close_page();
  147.     }
  148.     page_empty = 1;
  149. }
  150.  
  151. bool drvbase::pathsCanBeMerged(const PathInfo & path1, const PathInfo & path2)
  152. {
  153. //    return 0;
  154.     // two paths can be merged if one of them is a stroke and the
  155.     // other a fill AND
  156.     // all pathelements are the same
  157. //    errf << path1.numberOfElementsInPath << " " << path2.numberOfElementsInPath << endl;
  158.     if (((path1.currentShowType == stroke && path2.currentShowType == fill)  ||
  159.          (path2.currentShowType == stroke && path1.currentShowType == fill)  )
  160.        && (path1.numberOfElementsInPath == path2.numberOfElementsInPath)  ) {
  161. //        errf << "Pathes seem to be mergeable" << endl;
  162.         for (unsigned int i = 0; i < path1.numberOfElementsInPath ; i++) {
  163.             const basedrawingelement *bd1 = path1.path[i];
  164.             const basedrawingelement *bd2 = path2.path[i];
  165. //            if (! *(path1.path[i]) == *(path2.path[i]) ) return 0;
  166.             if (! (*bd1 == *bd2) ) return 0;
  167.         }
  168. //        errf << "Pathes are mergeable" << endl;
  169.         return 1;
  170.     } else {
  171.         return 0;
  172.     }
  173. }
  174.  
  175. void drvbase::addNumber(float co)
  176. {
  177. // printf("Adding %f\n",co);
  178.  if (nextFreeNumber < maxpoints) { 
  179.          numbers[nextFreeNumber++] = co; 
  180.          // nextFreeNumber always points to the next free number
  181.  } else { 
  182.        errf << "Too many numbers on stack. Please increase maxpoints in drvbase.h \n"; 
  183.  
  184.        exit(1); 
  185.  }
  186. }
  187.  
  188. const basedrawingelement & drvbase::pathElement(unsigned int index) const 
  189. {
  190.     return *(outputPath->path[index]);
  191. }
  192. bool operator==(const basedrawingelement & bd1, const basedrawingelement & bd2) 
  193.         { 
  194.             if (bd1.getType() != bd2.getType() ) {
  195.                 return 0;
  196.             } else {
  197.                 for (unsigned int i = 0; i < bd1.size; i++ ) {
  198.                     if (! (bd1.getPoint(i) == bd2.getPoint(i)) ) return 0;
  199.                 }
  200.             }
  201.             return 1;
  202.         }
  203.  
  204. void drvbase::dumpText(const char * const thetext)
  205. {
  206.   if (strlen(thetext) > 0) {
  207.       dumpPath(); // dump last path to avoid wrong sequence of text and graphics
  208.       add_to_page();
  209.       float y = pop();
  210.       float x = pop();
  211.       textInfo_.x = x;
  212.       textInfo_.y = y;
  213.       textInfo_.thetext = thetext;
  214.       show_text(textInfo_);
  215.   }
  216. }
  217.  
  218. float drvbase::pop() 
  219.   if (nextFreeNumber > 0) {
  220.       nextFreeNumber--;
  221.       return numbers[nextFreeNumber]; // the value we just popped
  222.   } else {
  223.     errf << "Fatal error in drvbase::pop : nextFreeNumber would get < 0" << endl;
  224.     exit(1);
  225.   }
  226.   return 0.0f; // never reached, just to make compiler quiet
  227. }
  228.  
  229. void drvbase::setCurrentWidthParams(float ax,float ay,int Char,float cx,float cy)
  230. {
  231.     textInfo_.ax = ax;
  232.     textInfo_.ay = ay;
  233.     textInfo_.Char = Char;
  234.     textInfo_.cx = cx;
  235.     textInfo_.cy = cy;
  236. }
  237.  
  238. void drvbase::setCurrentFontName(const char * const Name,bool is_non_standard_font) 
  239.     textInfo_.currentFontName.copy(Name); 
  240.     textInfo_.is_non_standard_font = is_non_standard_font;
  241. }
  242.  
  243. void drvbase::setCurrentFontFamilyName(const char * const Name)
  244.     { textInfo_.currentFontFamilyName.copy(Name); }
  245.  
  246. void drvbase::setCurrentFontFullName(const char * const Name)
  247.     { textInfo_.currentFontFullName.copy(Name); }
  248.  
  249. void drvbase::setCurrentFontWeight(const char * const Name)
  250.     { textInfo_.currentFontWeight.copy(Name); }
  251.  
  252. void drvbase::setCurrentFontSize(const float Size)
  253.     { /* errf << "setting Size to " << Size << endl; */  textInfo_.currentFontSize = Size ; }
  254.  
  255. void drvbase::setCurrentFontAngle(float value)
  256.     { textInfo_.currentFontAngle = value; }
  257.  
  258. bool drvbase::is_a_rectangle()
  259. {
  260. #if 0
  261. // TODO, Not yet implemented
  262.     int     dir;        /* 1 - up/down (same x) 0 - left/right (same y) */
  263.     if (numbersInCurrentSegment() != 10)
  264.     return 0;
  265. /* it might be a  rectangle */
  266.  
  267.     if (pNumber(0) == pNumber(2)) {
  268.     /* same x */
  269.     dir = 0;
  270.     } else if (pNumber(1) == pNumber(3)) {
  271.     /* same y */
  272.     dir = 1;
  273.     } else {
  274.     /* no rectangle */
  275.     return 0;
  276.     }
  277.  
  278.     for (int i = 0; i < 8; i++, i++) {
  279.     if (dir == 1) {
  280.         if (!(pNumber(i + 1) == pNumber(i + 1 + 2)))
  281.         return 0;
  282.         dir = 0;
  283.     } else {
  284.         if (!(pNumber(i) == pNumber(i + 2)))
  285.         return 0;
  286.         dir = 1;
  287.     }
  288.     }
  289.     return 1;
  290. #else
  291.     return 0;
  292. #endif
  293. }
  294.  
  295. void drvbase::add_to_page()
  296. {
  297.     if (page_empty) {
  298.     page_empty = 0;
  299.     currentPageNumber++;
  300.     open_page();
  301.     }
  302. }
  303.  
  304. void drvbase::guess_linetype()
  305. {
  306.     const char * pattern = dashPattern();
  307.     // first count number of ' ' in pattern to determine number of entries
  308.     // we normally have one less than number of blanks
  309.     // line looks like: " [ 2.25 6.75 ] 0.0 setdash"
  310.     drvbase::linetype curtype = solid;
  311.     int nr_of_entries = -1;
  312.     while ((*pattern) && (*pattern != ']' ) ) {
  313.         if (*pattern == ' ') nr_of_entries++;
  314.         pattern++;
  315.     }
  316.     pattern = dashPattern();
  317.     // errf << nr_of_entries << " entries found in " << pattern << endl;
  318.     if (nr_of_entries > 0) {
  319.         // now get the numbers
  320.         // repeat the numbers, if number of entries is odd
  321.         int rep = nr_of_entries % 2; // rep is 1 for odd numbers 0 for even
  322.         float *d_numbers = new float[nr_of_entries *(rep + 1)];
  323.         int cur = 0;
  324. #ifndef USEISTREAM
  325.         for (int i = 0; i <= rep ; i++ ) {
  326.             pattern = dashPattern();
  327.             while ((*pattern) && (*pattern != ']' ) ) {
  328.                 if (*pattern == ' ' && ( *(pattern+1) != ']' ) ) {
  329.                     float f = (float) atof(pattern);
  330.                     d_numbers[cur] = f;
  331.                      // errf << d_numbers[cur] << endl;
  332.                     cur++;
  333.                 }
  334.                 pattern++;
  335.             }
  336.         }
  337. #else
  338.         for (int i = 0; i <= rep ; i++ ) {
  339.             // on some systems istrstreams expects a non const char *
  340.             // so we need to make a copy
  341.             char * localpattern = new char[strlen(pattern+1) + 1];
  342.             strcpy(localpattern,pattern+1); // skip leading [
  343.             istrstream instream(localpattern); 
  344.             while (!instream.fail()) {
  345.                 float f;
  346.                 instream >> f;
  347.                 if (!instream.fail() ) {
  348.                     d_numbers[cur] = f;
  349.                      // errf << d_numbers[cur] << endl;
  350.                     cur++;
  351.                 }
  352.             }
  353.             delete [] localpattern;
  354.         }
  355. #endif
  356.         // now guess a pattern from
  357.         // solid, dashed, dotted, dashdot, dashdotdot ; // corresponding to the CGM patterns
  358.         switch ( nr_of_entries *(rep + 1) ) {
  359.         case 2: 
  360.             if (d_numbers[0] < 2.0f) {
  361.                 // if on is < 2 then always dotted
  362.                 // ok we miss '.             .             .'
  363.                 curtype = drvbase::dotted;
  364.             } else {
  365.                 curtype = drvbase::dashed;
  366.             }
  367.             break;
  368.         case 4:
  369.             if ( (d_numbers[0] < 2.0f) || (d_numbers[2] < 2.0f) ) {
  370.                 curtype = drvbase::dashdot;
  371.             } else {
  372.                 curtype = drvbase::dashed;
  373.             }
  374.             break;
  375.         case 6:
  376.             if ( (d_numbers[0] < 2.0f) || (d_numbers[2] < 2.0f)  || (d_numbers[2] < 2.0f) ) {
  377.                 curtype = drvbase::dashdotdot;
  378.             } else {
  379.                 curtype = drvbase::dashed;
  380.             }
  381.             break;
  382.         default:
  383.             curtype = drvbase::dashed;
  384.             break;
  385.         }
  386.         delete [] d_numbers;
  387.     } else {
  388.         // no entry
  389.         curtype = drvbase::solid;
  390.     }
  391.     // errf << "linetype from " << dashPattern() << " is " << curtype << endl;
  392.     setCurrentLineType(curtype);
  393. }
  394.  
  395. void drvbase::dumpPath()
  396. {
  397.     guess_linetype(); // needs to be done here, because we must write to currentpath
  398.     if (currentPath->numberOfElementsInPath == 2) {
  399.         // a polygon with two points is drawn as a line
  400.         currentPath->isPolygon=false;
  401.         currentPath->currentShowType=drvbase::stroke;
  402.     }
  403.     if (currentPath->currentShowType!=drvbase::stroke)
  404.     {
  405.         /* don't show border with fill */
  406.         setCurrentLineWidth(0.0f);  
  407.     }
  408.  
  409.     if (domerge && pathsCanBeMerged(p1,p2)) {
  410.     // make p1 the outputPath and clear p2
  411.     if (verbose) {
  412.         errf << "Path " << p1.nr << " type " << (int) p1.currentShowType << endl;
  413.         errf << p1.fillR << " " << p1.fillG << " " << p1.fillB << endl;
  414.         errf << p1.edgeR << " " << p1.edgeG << " " << p1.edgeB << endl;
  415.         errf << p1.currentLineWidth << endl;
  416.  
  417.         errf << "Path " << p2.nr << " type " << (int) p2.currentShowType << endl;
  418.         errf << p2.fillR << " " << p2.fillG << " " << p2.fillB << endl;
  419.         errf << p2.edgeR << " " << p2.edgeG << " " << p2.edgeB << endl;
  420.         errf << p2.currentLineWidth << endl;
  421.         errf << " have been merged\n";
  422.     }
  423.     // merge p2 into p1
  424.     if (p1.currentShowType == stroke) {
  425.         // p2 is the fill
  426.         p1.currentShowType = p2.currentShowType;
  427.         p1.fillR = p2.fillR;
  428.         p1.fillG = p2.fillG;
  429.         p1.fillB = p2.fillB;
  430.     } else {
  431.         // p1 is the fill, so copy the line parameters from p2
  432.         p1.currentLineWidth = p2.currentLineWidth;
  433.         p1.edgeR = p2.edgeR;
  434.         p1.edgeG = p2.edgeG;
  435.         p1.edgeB = p2.edgeB;
  436.     }
  437.     if (verbose) {
  438.         errf << " result is \n";
  439.         errf << "Path " << p1.nr << " type " << (int) p1.currentShowType << endl;
  440.         errf << p1.fillR << " " << p1.fillG << " " << p1.fillB << endl;
  441.         errf << p1.edgeR << " " << p1.edgeG << " " << p1.edgeB << endl;
  442.         errf << p1.currentLineWidth << endl;
  443.  
  444.     }
  445.     outputPath = &p1;
  446.     p2.clear();
  447.     } else {
  448.     outputPath = lastPath;
  449.     }
  450.     if (numberOfElementsInPath() > 0 ) {
  451.     // nothing to do for empty pathes
  452.     // pathes may be empty due to a merge operation
  453.  
  454.     if (verbose) {
  455.         errf << "working on";
  456.         switch ( currentShowType() ) {
  457.         case  drvbase::stroke:
  458.             errf << " stroked ";
  459.             break;
  460.         case  drvbase::fill:
  461.             errf << " filled ";
  462.             break;
  463.         case  drvbase::eofill:
  464.             errf << " eofilled ";
  465.             break;
  466.         default:
  467.             break;
  468.         }
  469.     errf << "path " << currentNr()  << " with " << 
  470.         numberOfElementsInPath() << " elements" << endl;
  471.     }
  472.  
  473.     if (numberOfElementsInPath() > 1) {
  474.     // cannot draw single points 
  475.         add_to_page();
  476.         if (isPolygon()) { /* PolyGon */
  477.         if (is_a_rectangle()) {
  478.             {
  479. #if 0
  480.             float llx,lly,urx,ury;
  481.  
  482. // TODO, Not yet implemented
  483.             llx = min( min(pNumber(0),pNumber(2)), min(pNumber(4),pNumber(6)));
  484.             urx = max( max(pNumber(0),pNumber(2)), max(pNumber(4),pNumber(6)));
  485.             lly = min( min(pNumber(1),pNumber(3)), min(pNumber(5),pNumber(7)));
  486.             ury = max( max(pNumber(1),pNumber(3)), max(pNumber(5),pNumber(7)));
  487.  
  488.             show_rectangle(llx,lly,urx,ury);
  489. #endif
  490.                    }
  491.         } else {
  492.             show_path();
  493.         }
  494.         } else { /* PolyLine */
  495.         show_path();
  496.         };
  497.     }
  498.     // cleanup
  499.     outputPath->clear();
  500.     }
  501.  
  502.  
  503.     // swap current and last pointers
  504.     PathInfo *help       = currentPath; 
  505.               currentPath = lastPath;
  506.               lastPath    = help;
  507.  
  508.     currentPath->copyInfo(*help); // initialize next path with state of last path
  509.                   // currentPath is the path filled next by lexer
  510.  
  511.     outputPath = currentPath;
  512. }
  513.  
  514. void    drvbase::addtopath(basedrawingelement * newelement)
  515. {
  516.     if (newelement) {
  517.         if (currentPath->numberOfElementsInPath < maxElements) {
  518.             currentPath->path[currentPath->numberOfElementsInPath] = newelement;
  519. #ifdef DEBUG
  520.             cout << "pathelement " << currentPath->numberOfElementsInPath << " added "
  521.                  << *newelement << endl;
  522. #endif
  523.             currentPath->numberOfElementsInPath++;
  524.         } else {
  525.             errf << "Fatal: number of path elements exceeded. Increase maxElements in drvbase.h" << endl;
  526.             exit(1);
  527.         }
  528.     } else {
  529.         errf << "Fatal: newelement is NULL in addtopath " << endl;
  530.         exit(1);
  531.     }
  532. }
  533.  
  534. void drvbase::PathInfo::clear() {
  535.             for (unsigned int i = 0 ; i < numberOfElementsInPath; i++ ) {
  536.                 delete path[i];
  537.                 path[i] = 0;
  538.             }
  539.             numberOfElementsInPath = 0;
  540.         }
  541. void drvbase::PathInfo::copyInfo(const PathInfo & p){
  542.             // copies the whole path state except the path array
  543.             currentShowType = p.currentShowType;
  544.             nr = p.nr;
  545.             // Path is not copied path(0),
  546.             isPolygon = p.isPolygon;
  547.             // numberOfElementsInPath = p.numberOfElementsInPath;
  548.             currentLineWidth = p.currentLineWidth;
  549.             edgeR = p.edgeR;
  550.             edgeG = p.edgeG;
  551.             edgeB = p.edgeB;
  552.             fillR = p.fillR;
  553.             fillG = p.fillG;
  554.             fillB = p.fillB;
  555.         }
  556.  
  557. ostream & operator<<(ostream & out,const basedrawingelement &elem)
  558. {
  559.     out << "type: " << (int) elem.getType() << " params: " ;
  560.     for (unsigned int i = 0 ; i < elem.size ; i++ ) {
  561.         out << elem.getPoint(i).x_ << " "
  562.             << elem.getPoint(i).y_ << " "; 
  563.     }
  564.     out << endl;
  565.     return out;
  566. }
  567. ColorTable::ColorTable(const char * const * defaultColors,
  568.            const unsigned int numberOfDefaultColors,
  569.            makeColorNameType makeColorName)  :
  570.         defaultColors_(defaultColors),
  571.         numberOfDefaultColors_(numberOfDefaultColors),
  572.         makeColorName_(makeColorName) 
  573.     for (unsigned int i = 0 ; i< maxcolors; i++) newColors[i] = 0;
  574. }
  575.  
  576. ColorTable::~ColorTable() 
  577. {
  578.     unsigned int current= 0;
  579.     while (newColors[current] != 0) {
  580.         delete [] newColors[current];
  581.         current++;
  582.     }
  583. }
  584.  
  585. unsigned int ColorTable::getColorIndex(float r, float g, float b)
  586. {
  587. // registers a possibly new color and returns the index 
  588. // under which the color was registered
  589.     const char * cmp = makeColorName_(r,g,b);
  590.     for (unsigned int i = 0; i < numberOfDefaultColors_ ; i++ )
  591.     {
  592.         if (strcmp(cmp,defaultColors_[i]) == 0) {
  593.             return i;
  594.         }
  595.     }
  596. // look in new colors
  597.     unsigned int j = 0;
  598.     for (j = 0; ((j < maxcolors) && (newColors[j] != 0)) ; j++ )
  599.     {
  600.         if (strcmp(cmp,newColors[j]) == 0) {
  601.             return j+numberOfDefaultColors_;
  602.         }
  603.     }
  604. // not found so far
  605. // j is either maxcolors or the index of the next free entry
  606. // add a copy to newColors
  607.     if (j < maxcolors) {
  608.         newColors[j] = new char[strlen(cmp) +1];
  609.         strcpy(newColors[j],cmp);
  610.         return j+numberOfDefaultColors_;
  611.     } else {
  612. //        cerr << "running out of colors" << endl;
  613.         return 0;
  614.     }
  615.  
  616. }
  617.  
  618. const char * const ColorTable::getColorString(float r, float g, float b)
  619. {
  620.     return getColorString(getColorIndex(r,g,b));
  621. }
  622.  
  623. bool ColorTable::isKnownColor(float r, float g, float b) const
  624. {
  625. // Possible improvements:
  626. // could return the next free entry as negative number in case
  627. // the color is not found. This would make it possible to
  628. // use this function in getColorEntry as well, or (better)
  629. // make a pure registercolor(index,.....) instead of
  630. // getColorEntry.
  631.     const char * cmp = makeColorName_(r,g,b);
  632.     for (unsigned int i = 0; i < numberOfDefaultColors_ ; i++ )
  633.     {
  634.         if (strcmp(cmp,defaultColors_[i]) == 0) {
  635.             return true;
  636.         }
  637.     }
  638.     // look in new colors
  639.     unsigned int j = 0;
  640.     for (j = 0; ((j < maxcolors) && (newColors[j] != 0)) ; j++ )
  641.     {
  642.         if (strcmp(cmp,newColors[j]) == 0) {
  643.             return true; // j+numberOfDefaultColors_;
  644.         }
  645.     }
  646.     // not found so far
  647.     return false; 
  648. }
  649.  
  650. const char * const ColorTable::getColorString(unsigned int index) const
  651. {
  652.     return (index < numberOfDefaultColors_) ? defaultColors_[index] :
  653.                             newColors[index - numberOfDefaultColors_];
  654. }
  655.