home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / x / x11r6-ch / xpm-3.4 / xpm-3 / xpm-3.4c / lib / parse.c < prev    next >
C/C++ Source or Header  |  1994-06-06  |  19KB  |  716 lines

  1. /*
  2.  * Copyright (C) 1989-94 GROUPE BULL
  3.  *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  5.  * of this software and associated documentation files (the "Software"), to
  6.  * deal in the Software without restriction, including without limitation the
  7.  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8.  * sell copies of the Software, and to permit persons to whom the Software is
  9.  * furnished to do so, subject to the following conditions:
  10.  *
  11.  * The above copyright notice and this permission notice shall be included in
  12.  * all copies or substantial portions of the Software.
  13.  *
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17.  * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  18.  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  19.  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  20.  *
  21.  * Except as contained in this notice, the name of GROUPE BULL shall not be
  22.  * used in advertising or otherwise to promote the sale, use or other dealings
  23.  * in this Software without prior written authorization from GROUPE BULL.
  24.  */
  25.  
  26. /*****************************************************************************\
  27. * parse.c:                                                                    *
  28. *                                                                             *
  29. *  XPM library                                                                *
  30. *  Parse an XPM file or array and store the found informations                *
  31. *  in the given XpmImage structure.                                           *
  32. *                                                                             *
  33. *  Developed by Arnaud Le Hors                                                *
  34. \*****************************************************************************/
  35.  
  36. /*
  37.  * The code related to FOR_MSW has been added by
  38.  * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
  39.  */
  40.  
  41. #include "xpmP.h"
  42. #ifdef VMS
  43. #include "sys$library:ctype.h"
  44. #else
  45. #include <ctype.h>
  46. #endif
  47.  
  48. LFUNC(ParseValues, int, (xpmData *data, unsigned int *width,
  49.              unsigned int *height, unsigned int *ncolors,
  50.              unsigned int *cpp, unsigned int *x_hotspot,
  51.              unsigned int *y_hotspot, unsigned int *hotspot,
  52.              unsigned int *extensions));
  53.  
  54. LFUNC(ParseColors, int, (xpmData *data, unsigned int ncolors, unsigned int cpp,
  55.              XpmColor **colorTablePtr, xpmHashTable *hashtable));
  56.  
  57. LFUNC(ParsePixels, int, (xpmData *data, unsigned int width,
  58.              unsigned int height, unsigned int ncolors,
  59.              unsigned int cpp, XpmColor *colorTable,
  60.              xpmHashTable *hashtable, unsigned int **pixels));
  61.  
  62. LFUNC(ParseExtensions, int, (xpmData *data, XpmExtension **extensions,
  63.                  unsigned int *nextensions));
  64.  
  65. char *xpmColorKeys[] = {
  66.     "s",                /* key #1: symbol */
  67.     "m",                /* key #2: mono visual */
  68.     "g4",                /* key #3: 4 grays visual */
  69.     "g",                /* key #4: gray visual */
  70.     "c",                /* key #5: color visual */
  71. };
  72.  
  73.  
  74. /* function call in case of error, frees only locally allocated variables */
  75. #undef RETURN
  76. #define RETURN(status) \
  77. { \
  78.     if (colorTable) xpmFreeColorTable(colorTable, ncolors); \
  79.     if (pixelindex) XpmFree(pixelindex); \
  80.     if (hints_cmt)  XpmFree(hints_cmt); \
  81.     if (colors_cmt) XpmFree(colors_cmt); \
  82.     if (pixels_cmt) XpmFree(pixels_cmt); \
  83.     return(status); \
  84. }
  85.  
  86. /*
  87.  * This function parses an Xpm file or data and store the found informations
  88.  * in an an XpmImage structure which is returned.
  89.  */
  90. int
  91. xpmParseData(data, image, info)
  92.     xpmData *data;
  93.     XpmImage *image;
  94.     XpmInfo *info;
  95. {
  96.     /* variables to return */
  97.     unsigned int width, height, ncolors, cpp;
  98.     unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0;
  99.     XpmColor *colorTable = NULL;
  100.     unsigned int *pixelindex = NULL;
  101.     char *hints_cmt = NULL;
  102.     char *colors_cmt = NULL;
  103.     char *pixels_cmt = NULL;
  104.  
  105.     unsigned int cmts;
  106.     int ErrorStatus;
  107.     xpmHashTable hashtable;
  108.  
  109.     cmts = info && (info->valuemask & XpmReturnComments);
  110.  
  111.     /*
  112.      * parse the header
  113.      */
  114.     ErrorStatus = xpmParseHeader(data);
  115.     if (ErrorStatus != XpmSuccess)
  116.     return (ErrorStatus);
  117.  
  118.     /*
  119.      * read values
  120.      */
  121.     ErrorStatus = ParseValues(data, &width, &height, &ncolors, &cpp,
  122.                 &x_hotspot, &y_hotspot, &hotspot, &extensions);
  123.     if (ErrorStatus != XpmSuccess)
  124.     return (ErrorStatus);
  125.  
  126.     /*
  127.      * store the hints comment line
  128.      */
  129.     if (cmts)
  130.     xpmGetCmt(data, &hints_cmt);
  131.  
  132.     /*
  133.      * init the hastable
  134.      */
  135.     if (USE_HASHTABLE) {
  136.     ErrorStatus = xpmHashTableInit(&hashtable);
  137.     if (ErrorStatus != XpmSuccess)
  138.         return (ErrorStatus);
  139.     }
  140.  
  141.     /*
  142.      * read colors
  143.      */
  144.     ErrorStatus = ParseColors(data, ncolors, cpp, &colorTable, &hashtable);
  145.     if (ErrorStatus != XpmSuccess)
  146.     RETURN(ErrorStatus);
  147.  
  148.     /*
  149.      * store the colors comment line
  150.      */
  151.     if (cmts)
  152.     xpmGetCmt(data, &colors_cmt);
  153.  
  154.     /*
  155.      * read pixels and index them on color number
  156.      */
  157.     ErrorStatus = ParsePixels(data, width, height, ncolors, cpp, colorTable,
  158.                   &hashtable, &pixelindex);
  159.  
  160.     /*
  161.      * free the hastable
  162.      */
  163.     if (USE_HASHTABLE)
  164.     xpmHashTableFree(&hashtable);
  165.  
  166.     if (ErrorStatus != XpmSuccess)
  167.     RETURN(ErrorStatus);
  168.  
  169.     /*
  170.      * store the pixels comment line
  171.      */
  172.     if (cmts)
  173.     xpmGetCmt(data, &pixels_cmt);
  174.  
  175.     /*
  176.      * parse extensions
  177.      */
  178.     if (info && (info->valuemask & XpmReturnExtensions))
  179.     if (extensions) {
  180.         ErrorStatus = ParseExtensions(data, &info->extensions,
  181.                       &info->nextensions);
  182.         if (ErrorStatus != XpmSuccess)
  183.         RETURN(ErrorStatus);
  184.     } else {
  185.         info->extensions = NULL;
  186.         info->nextensions = 0;
  187.     }
  188.  
  189.     /*
  190.      * store found informations in the XpmImage structure
  191.      */
  192.     image->width = width;
  193.     image->height = height;
  194.     image->cpp = cpp;
  195.     image->ncolors = ncolors;
  196.     image->colorTable = colorTable;
  197.     image->data = pixelindex;
  198.  
  199.     if (info) {
  200.     if (cmts) {
  201.         info->hints_cmt = hints_cmt;
  202.         info->colors_cmt = colors_cmt;
  203.         info->pixels_cmt = pixels_cmt;
  204.     }
  205.     if (hotspot) {
  206.         info->x_hotspot = x_hotspot;
  207.         info->y_hotspot = y_hotspot;
  208.         info->valuemask |= XpmHotspot;
  209.     }
  210.     }
  211.     return (XpmSuccess);
  212. }
  213.  
  214. static int
  215. ParseValues(data, width, height, ncolors, cpp,
  216.         x_hotspot, y_hotspot, hotspot, extensions)
  217.     xpmData *data;
  218.     unsigned int *width, *height, *ncolors, *cpp;
  219.     unsigned int *x_hotspot, *y_hotspot, *hotspot;
  220.     unsigned int *extensions;
  221. {
  222.     unsigned int l;
  223.     char buf[BUFSIZ];
  224.  
  225.     if (!data->format) {        /* XPM 2 or 3 */
  226.  
  227.     /*
  228.      * read values: width, height, ncolors, chars_per_pixel
  229.      */
  230.     if (!(xpmNextUI(data, width) && xpmNextUI(data, height)
  231.           && xpmNextUI(data, ncolors) && xpmNextUI(data, cpp)))
  232.         return (XpmFileInvalid);
  233.  
  234.     /*
  235.      * read optional information (hotspot and/or XPMEXT) if any
  236.      */
  237.     l = xpmNextWord(data, buf, BUFSIZ);
  238.     if (l) {
  239.         *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
  240.         if (*extensions)
  241.         *hotspot = (xpmNextUI(data, x_hotspot)
  242.                 && xpmNextUI(data, y_hotspot));
  243.         else {
  244.         *hotspot = (atoui(buf, l, x_hotspot)
  245.                 && xpmNextUI(data, y_hotspot));
  246.         l = xpmNextWord(data, buf, BUFSIZ);
  247.         *extensions = (l == 6 && !strncmp("XPMEXT", buf, 6));
  248.         }
  249.     }
  250.     } else {
  251.  
  252.     /*
  253.      * XPM 1 file read values: width, height, ncolors, chars_per_pixel
  254.      */
  255.     int i;
  256.     char *ptr;
  257.  
  258.     for (i = 0; i < 4; i++) {
  259.         l = xpmNextWord(data, buf, BUFSIZ);
  260.         if (l != 7 || strncmp("#define", buf, 7))
  261.         return (XpmFileInvalid);
  262.         l = xpmNextWord(data, buf, BUFSIZ);
  263.         if (!l)
  264.         return (XpmFileInvalid);
  265.         ptr = index(buf, '_');
  266.         if (!ptr)
  267.         return (XpmFileInvalid);
  268.         switch (l - (ptr - buf)) {
  269.         case 6:
  270.         if (!strncmp("_width", ptr, 6) && !xpmNextUI(data, width))
  271.             return (XpmFileInvalid);
  272.         break;
  273.         case 7:
  274.         if (!strncmp("_height", ptr, 7) && !xpmNextUI(data, height))
  275.             return (XpmFileInvalid);
  276.         break;
  277.         case 8:
  278.         if (!strncmp("_ncolors", ptr, 8) && !xpmNextUI(data, ncolors))
  279.             return (XpmFileInvalid);
  280.         break;
  281.         case 16:
  282.         if (!strncmp("_chars_per_pixel", ptr, 16)
  283.             && !xpmNextUI(data, cpp))
  284.             return (XpmFileInvalid);
  285.         break;
  286.         default:
  287.         return (XpmFileInvalid);
  288.         }
  289.         /* skip the end of line */
  290.         xpmNextString(data);
  291.     }
  292.     *hotspot = 0;
  293.     *extensions = 0;
  294.     }
  295.     return (XpmSuccess);
  296. }
  297.  
  298. static int
  299. ParseColors(data, ncolors, cpp, colorTablePtr, hashtable)
  300.     xpmData *data;
  301.     unsigned int ncolors;
  302.     unsigned int cpp;
  303.     XpmColor **colorTablePtr;
  304.     xpmHashTable *hashtable;
  305. {
  306.     unsigned int key, l, a, b;
  307.     unsigned int curkey;        /* current color key */
  308.     unsigned int lastwaskey;        /* key read */
  309.     char buf[BUFSIZ];
  310.     char curbuf[BUFSIZ];        /* current buffer */
  311.     char **sptr, *s;
  312.     XpmColor *color;
  313.     XpmColor *colorTable;
  314.     char **defaults;
  315.     int ErrorStatus;
  316.  
  317.     colorTable = (XpmColor *) XpmCalloc(ncolors, sizeof(XpmColor));
  318.     if (!colorTable)
  319.     return (XpmNoMemory);
  320.  
  321.     if (!data->format) {        /* XPM 2 or 3 */
  322.     for (a = 0, color = colorTable; a < ncolors; a++, color++) {
  323.         xpmNextString(data);    /* skip the line */
  324.  
  325.         /*
  326.          * read pixel value
  327.          */
  328.         color->string = (char *) XpmMalloc(cpp + 1);
  329.         if (!color->string) {
  330.         xpmFreeColorTable(colorTable, ncolors);
  331.         return (XpmNoMemory);
  332.         }
  333.         for (b = 0, s = color->string; b < cpp; b++, s++)
  334.         *s = xpmGetC(data);
  335.         *s = '\0';
  336.  
  337.         /*
  338.          * store the string in the hashtable with its color index number
  339.          */
  340.         if (USE_HASHTABLE) {
  341.         ErrorStatus =
  342.             xpmHashIntern(hashtable, color->string, HashAtomData(a));
  343.         if (ErrorStatus != XpmSuccess) {
  344.             xpmFreeColorTable(colorTable, ncolors);
  345.             return (ErrorStatus);
  346.         }
  347.         }
  348.  
  349.         /*
  350.          * read color keys and values
  351.          */
  352.         defaults = (char **) color;
  353.         curkey = 0;
  354.         lastwaskey = 0;
  355.         *curbuf = '\0';        /* init curbuf */
  356.         while (l = xpmNextWord(data, buf, BUFSIZ)) {
  357.         if (!lastwaskey) {
  358.             for (key = 0, sptr = xpmColorKeys; key < NKEYS; key++,
  359.              sptr++)
  360.             if ((strlen(*sptr) == l) && (!strncmp(*sptr, buf, l)))
  361.                 break;
  362.         }
  363.         if (!lastwaskey && key < NKEYS) {    /* open new key */
  364.             if (curkey) {    /* flush string */
  365.             s = (char *) XpmMalloc(strlen(curbuf) + 1);
  366.             if (!s) {
  367.                 xpmFreeColorTable(colorTable, ncolors);
  368.                 return (XpmNoMemory);
  369.             }
  370.             defaults[curkey] = s;
  371.             strcpy(s, curbuf);
  372.             }
  373.             curkey = key + 1;    /* set new key  */
  374.             *curbuf = '\0';    /* reset curbuf */
  375.             lastwaskey = 1;
  376.         } else {
  377.             if (!curkey) {    /* key without value */
  378.             xpmFreeColorTable(colorTable, ncolors);
  379.             return (XpmFileInvalid);
  380.             }
  381.             if (!lastwaskey)
  382.             strcat(curbuf, " ");    /* append space */
  383.             buf[l] = '\0';
  384.             strcat(curbuf, buf);/* append buf */
  385.             lastwaskey = 0;
  386.         }
  387.         }
  388.         if (!curkey) {        /* key without value */
  389.         xpmFreeColorTable(colorTable, ncolors);
  390.         return (XpmFileInvalid);
  391.         }
  392.         s = defaults[curkey] = (char *) XpmMalloc(strlen(curbuf) + 1);
  393.         if (!s) {
  394.         xpmFreeColorTable(colorTable, ncolors);
  395.         return (XpmNoMemory);
  396.         }
  397.         strcpy(s, curbuf);
  398.     }
  399.     } else {                /* XPM 1 */
  400.     /* get to the beginning of the first string */
  401.     data->Bos = '"';
  402.     data->Eos = '\0';
  403.     xpmNextString(data);
  404.     data->Eos = '"';
  405.     for (a = 0, color = colorTable; a < ncolors; a++, color++) {
  406.  
  407.         /*
  408.          * read pixel value
  409.          */
  410.         color->string = (char *) XpmMalloc(cpp + 1);
  411.         if (!color->string) {
  412.         xpmFreeColorTable(colorTable, ncolors);
  413.         return (XpmNoMemory);
  414.         }
  415.         for (b = 0, s = color->string; b < cpp; b++, s++)
  416.         *s = xpmGetC(data);
  417.         *s = '\0';
  418.  
  419.         /*
  420.          * store the string in the hashtable with its color index number
  421.          */
  422.         if (USE_HASHTABLE) {
  423.         ErrorStatus =
  424.             xpmHashIntern(hashtable, color->string, HashAtomData(a));
  425.         if (ErrorStatus != XpmSuccess) {
  426.             xpmFreeColorTable(colorTable, ncolors);
  427.             return (ErrorStatus);
  428.         }
  429.         }
  430.  
  431.         /*
  432.          * read color values
  433.          */
  434.         xpmNextString(data);    /* get to the next string */
  435.         *curbuf = '\0';        /* init curbuf */
  436.         while (l = xpmNextWord(data, buf, BUFSIZ)) {
  437.         if (*curbuf != '\0')
  438.             strcat(curbuf, " ");/* append space */
  439.         buf[l] = '\0';
  440.         strcat(curbuf, buf);    /* append buf */
  441.         }
  442.         s = (char *) XpmMalloc(strlen(curbuf) + 1);
  443.         if (!s) {
  444.         xpmFreeColorTable(colorTable, ncolors);
  445.         return (XpmNoMemory);
  446.         }
  447.         strcpy(s, curbuf);
  448.         color->c_color = s;
  449.         *curbuf = '\0';        /* reset curbuf */
  450.         if (a < ncolors - 1)
  451.         xpmNextString(data);    /* get to the next string */
  452.     }
  453.     }
  454.     *colorTablePtr = colorTable;
  455.     return (XpmSuccess);
  456. }
  457.  
  458. static int
  459. ParsePixels(data, width, height, ncolors, cpp, colorTable, hashtable, pixels)
  460.     xpmData *data;
  461.     unsigned int width;
  462.     unsigned int height;
  463.     unsigned int ncolors;
  464.     unsigned int cpp;
  465.     XpmColor *colorTable;
  466.     xpmHashTable *hashtable;
  467.     unsigned int **pixels;
  468. {
  469.     unsigned int *iptr, *iptr2;
  470.     unsigned int a, x, y;
  471.  
  472. #ifndef FOR_MSW
  473.     iptr2 = (unsigned int *) XpmMalloc(sizeof(unsigned int) * width * height);
  474. #else
  475.  
  476.     /*
  477.      * special treatment to trick DOS malloc(size_t) where size_t is 16 bit!!
  478.      * XpmMalloc is defined to longMalloc(long) and checks the 16 bit boundary
  479.      */
  480.     iptr2 = (unsigned int *)
  481.     XpmMalloc((long) sizeof(unsigned int) * (long) width * (long) height);
  482. #endif
  483.     if (!iptr2)
  484.     return (XpmNoMemory);
  485.  
  486.     iptr = iptr2;
  487.  
  488.     switch (cpp) {
  489.  
  490.     case (1):                /* Optimize for single character
  491.                      * colors */
  492.     {
  493.         unsigned short colidx[256];
  494.  
  495.         bzero(colidx, 256 * sizeof(short));
  496.         for (a = 0; a < ncolors; a++)
  497.         colidx[colorTable[a].string[0]] = a + 1;
  498.  
  499.         for (y = 0; y < height; y++) {
  500.         xpmNextString(data);
  501.         for (x = 0; x < width; x++, iptr++) {
  502.             int idx = colidx[xpmGetC(data)];
  503.  
  504.             if (idx != 0)
  505.             *iptr = idx - 1;
  506.             else {
  507.             XpmFree(iptr2);
  508.             return (XpmFileInvalid);
  509.             }
  510.         }
  511.         }
  512.     }
  513.     break;
  514.  
  515.     case (2):                /* Optimize for double character
  516.                      * colors */
  517.     {
  518.  
  519. /* free all allocated pointers at all exits */
  520. #define FREE_CIDX {int f; for (f = 0; f < 256; f++) \
  521. if (cidx[f]) XpmFree(cidx[f]);}
  522.  
  523.         /* array of pointers malloced by need */
  524.         unsigned short *cidx[256];
  525.         int char1;
  526.  
  527.         bzero(cidx, 256 * sizeof(unsigned short *)); /* init */
  528.         for (a = 0; a < ncolors; a++) {
  529.         char1 = colorTable[a].string[0];
  530.         if (cidx[char1] == NULL) { /* get new memory */
  531.             cidx[char1] = (unsigned short *)
  532.             XpmCalloc(256, sizeof(unsigned short));
  533.             if (cidx[char1] == NULL) { /* new block failed */
  534.             FREE_CIDX;
  535.             XpmFree(iptr2);
  536.             return (XpmNoMemory);
  537.             }
  538.         }
  539.         cidx[char1][colorTable[a].string[1]] = a + 1;
  540.         }
  541.  
  542.         for (y = 0; y < height; y++) {
  543.         xpmNextString(data);
  544.         for (x = 0; x < width; x++, iptr++) {
  545.             int cc1 = xpmGetC(data);
  546.             int idx = cidx[cc1][xpmGetC(data)];
  547.  
  548.             if (idx != 0)
  549.             *iptr = idx - 1;
  550.             else {
  551.             FREE_CIDX;
  552.             XpmFree(iptr2);
  553.             return (XpmFileInvalid);
  554.             }
  555.         }
  556.         }
  557.         FREE_CIDX;
  558.     }
  559.     break;
  560.  
  561.     default:                /* Non-optimized case of long color
  562.                      * names */
  563.     {
  564.         char *s;
  565.         char buf[BUFSIZ];
  566.  
  567.         buf[cpp] = '\0';
  568.         if (USE_HASHTABLE) {
  569.         xpmHashAtom *slot;
  570.  
  571.         for (y = 0; y < height; y++) {
  572.             xpmNextString(data);
  573.             for (x = 0; x < width; x++, iptr++) {
  574.             for (a = 0, s = buf; a < cpp; a++, s++)
  575.                 *s = xpmGetC(data);
  576.             slot = xpmHashSlot(hashtable, buf);
  577.             if (!*slot) {    /* no color matches */
  578.                 XpmFree(iptr2);
  579.                 return (XpmFileInvalid);
  580.             }
  581.             *iptr = HashColorIndex(slot);
  582.             }
  583.         }
  584.         } else {
  585.         for (y = 0; y < height; y++) {
  586.             xpmNextString(data);
  587.             for (x = 0; x < width; x++, iptr++) {
  588.             for (a = 0, s = buf; a < cpp; a++, s++)
  589.                 *s = xpmGetC(data);
  590.             for (a = 0; a < ncolors; a++)
  591.                 if (!strcmp(colorTable[a].string, buf))
  592.                 break;
  593.             if (a == ncolors) {    /* no color matches */
  594.                 XpmFree(iptr2);
  595.                 return (XpmFileInvalid);
  596.             }
  597.             *iptr = a;
  598.             }
  599.         }
  600.         }
  601.     }
  602.     break;
  603.     }
  604.     *pixels = iptr2;
  605.     return (XpmSuccess);
  606. }
  607.  
  608. static int
  609. ParseExtensions(data, extensions, nextensions)
  610.     xpmData *data;
  611.     XpmExtension **extensions;
  612.     unsigned int *nextensions;
  613. {
  614.     XpmExtension *exts = NULL, *ext;
  615.     unsigned int num = 0;
  616.     unsigned int nlines, a, l, notstart, notend = 0;
  617.     int status;
  618.     char *string, *s, *s2, **sp;
  619.  
  620.     xpmNextString(data);
  621.     exts = (XpmExtension *) XpmMalloc(sizeof(XpmExtension));
  622.     /* get the whole string */
  623.     status = xpmGetString(data, &string, &l);
  624.     if (status != XpmSuccess) {
  625.     XpmFree(exts);
  626.     return (status);
  627.     }
  628.     /* look for the key word XPMEXT, skip lines before this */
  629.     while ((notstart = strncmp("XPMEXT", string, 6))
  630.        && (notend = strncmp("XPMENDEXT", string, 9))) {
  631.     XpmFree(string);
  632.     xpmNextString(data);
  633.     status = xpmGetString(data, &string, &l);
  634.     if (status != XpmSuccess) {
  635.         XpmFree(exts);
  636.         return (status);
  637.     }
  638.     }
  639.     if (!notstart)
  640.     notend = strncmp("XPMENDEXT", string, 9);
  641.     while (!notstart && notend) {
  642.     /* there starts an extension */
  643.     ext = (XpmExtension *)
  644.         XpmRealloc(exts, (num + 1) * sizeof(XpmExtension));
  645.     if (!ext) {
  646.         XpmFree(string);
  647.         XpmFreeExtensions(exts, num);
  648.         return (XpmNoMemory);
  649.     }
  650.     exts = ext;
  651.     ext += num;
  652.     /* skip whitespace and store its name */
  653.     s2 = s = string + 6;
  654.     while (isspace(*s2))
  655.         s2++;
  656.     a = s2 - s;
  657.     ext->name = (char *) XpmMalloc(l - a - 6);
  658.     if (!ext->name) {
  659.         XpmFree(string);
  660.         ext->lines = NULL;
  661.         ext->nlines = 0;
  662.         XpmFreeExtensions(exts, num + 1);
  663.         return (XpmNoMemory);
  664.     }
  665.     strncpy(ext->name, s + a, l - a - 6);
  666.     XpmFree(string);
  667.     /* now store the related lines */
  668.     xpmNextString(data);
  669.     status = xpmGetString(data, &string, &l);
  670.     if (status != XpmSuccess) {
  671.         ext->lines = NULL;
  672.         ext->nlines = 0;
  673.         XpmFreeExtensions(exts, num + 1);
  674.         return (status);
  675.     }
  676.     ext->lines = (char **) XpmMalloc(sizeof(char *));
  677.     nlines = 0;
  678.     while ((notstart = strncmp("XPMEXT", string, 6))
  679.            && (notend = strncmp("XPMENDEXT", string, 9))) {
  680.         sp = (char **)
  681.         XpmRealloc(ext->lines, (nlines + 1) * sizeof(char *));
  682.         if (!sp) {
  683.         XpmFree(string);
  684.         ext->nlines = nlines;
  685.         XpmFreeExtensions(exts, num + 1);
  686.         return (XpmNoMemory);
  687.         }
  688.         ext->lines = sp;
  689.         ext->lines[nlines] = string;
  690.         nlines++;
  691.         xpmNextString(data);
  692.         status = xpmGetString(data, &string, &l);
  693.         if (status != XpmSuccess) {
  694.         ext->nlines = nlines;
  695.         XpmFreeExtensions(exts, num + 1);
  696.         return (status);
  697.         }
  698.     }
  699.     if (!nlines) {
  700.         XpmFree(ext->lines);
  701.         ext->lines = NULL;
  702.     }
  703.     ext->nlines = nlines;
  704.     num++;
  705.     }
  706.     if (!num) {
  707.     XpmFree(string);
  708.     XpmFree(exts);
  709.     exts = NULL;
  710.     } else if (!notend)
  711.     XpmFree(string);
  712.     *nextensions = num;
  713.     *extensions = exts;
  714.     return (XpmSuccess);
  715. }
  716.