"Fossies" - the Fresh Open Source Software Archive

Member "unipkg-0.6.5/unipkglib/unipkg-slackdb.c" (16 Dec 2005, 47367 Bytes) of package /linux/privat/old/unipkg-0.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /******************************************************************************\
    2 *                                                                              *
    3 * UNIPKG (c) iSteve <isteve@bofh.cz>, 2005                                     *
    4 *                                                                              *
    5 * Universal PacKaGer.                                                          *
    6 * Licensed under GNU/GPL - if you don't like the software, fix it!             *
    7 *                                                                              *
    8 \******************************************************************************/
    9 
   10 ///////////////////////////////////////////////////////////////////////////////
   11 //                                                                           //
   12 // B A S E   I N C L U S I O N S   A N D   D E F I N I T I O N S             //
   13 //                                                                           //
   14 ///////////////////////////////////////////////////////////////////////////////
   15 #define _GNU_SOURCE
   16 
   17 #include <stdlib.h>
   18 #include <stdio.h>
   19 #include <string.h>
   20 #include <unistd.h>
   21 #include <fnmatch.h>
   22 #include <errno.h>
   23 #include <dlfcn.h>
   24 #include <libgen.h>
   25 #include <dirent.h>
   26 #include <fcntl.h>
   27 #include <ctype.h>
   28 
   29 #include <sys/stat.h>
   30 #include <sys/mman.h>
   31 #include <sys/types.h>
   32 
   33 #include "../common.h"
   34 
   35 // Decide on slack parser to be used //////////////////////////////////////////
   36 #define SLACK_COMPLEX
   37 ///////////////////////////////////////////////////////////////////////////////
   38 
   39 // Shell parsing definitions //////////////////////////////////////////////////
   40 #define PNONE       0
   41 #define FLAG        1
   42 #define DATA        2
   43 #define PMASK       3       // Mask for all base pstatus stuff
   44 
   45 #define PNOFLAG     4       // This is sort of extra
   46 
   47 #define QNONE       8
   48 #define QSINGLE     16
   49 #define QDOUBLE     32
   50 #define QMAKS       56
   51 
   52 #define QSUBSHELL   64
   53 
   54 #define NODATA      0
   55 #define SPACEDATA   1
   56 #define EQUIDATA    2
   57 
   58 #define SHORTOPT    0
   59 #define LONGOPT     1
   60 
   61 #define NONFREE(ptr)    ((*ptr != ' ') && (*ptr != '\t') && (*ptr != '\n') && (*ptr != ';'))
   62 
   63 #define SCLEAR      0
   64 #define SBLOCK      1
   65 
   66 typedef struct {
   67     char        **names;
   68     unsigned long   count;
   69 } shellbuiltins;
   70 
   71 typedef struct {
   72     char        *flag;              // like --suffix= ...
   73     unsigned long   flaglen;
   74     int     data;
   75     int     type;               // short, long
   76 } paramflag;
   77 
   78 typedef struct {
   79     char        *content;
   80     int     id;                 // -1 if ordinary data, 0+ if some flag
   81 } outformat;
   82 
   83 typedef struct {
   84     char        *fbase;             // Such as 'ln '.
   85     int     magic;              // For further use
   86     
   87     unsigned long   outcount, flagcount;
   88     
   89     outformat   *outputs;
   90     paramflag   *flags;
   91 } funcdef;
   92 
   93 typedef struct {
   94     char        *pwd;
   95     int     status;
   96 } subshell;
   97 ///////////////////////////////////////////////////////////////////////////////
   98 
   99 // Trivial parser definitions /////////////////////////////////////////////////
  100 #ifndef SLACK_COMPLEX
  101 typedef struct {
  102     char        *linkfile;
  103     char        *target;
  104 } linkinfo;
  105 #endif
  106 ///////////////////////////////////////////////////////////////////////////////
  107 
  108 
  109 
  110 typedef struct {
  111     char        *fpath;
  112     struct dirent   **namelist;
  113     long        curname;
  114     long        namecount;
  115 } dbhandle;
  116 
  117 struct treeNode {
  118     struct treeNode *child;
  119     struct treeNode *sibling;
  120     struct treeNode *parent;
  121     char *name;
  122 };
  123 
  124 ///////////////////////////////////////////////////////////////////////////////
  125 //                                                                           //
  126 // B A S E   F U N C T I O N S                                               //
  127 //                                                                           //
  128 ///////////////////////////////////////////////////////////////////////////////
  129 
  130 // GETCTRLHDR()
  131 //
  132 // Parses information from Slackware style packagedb description.
  133 //
  134 // Parameters:
  135 //   the part of status file regarding one package
  136 //   the header we are looking for
  137 //
  138 // Return value:
  139 //   NULL in error
  140 //   malloced value of the header otherwise
  141 static char *getctrlhdr(char *fullfile, char *hdr, unsigned long len) {
  142     char    *ptr, *end, *endptr;
  143     
  144     ptr = fullfile;
  145     if ((endptr = pstrnstr(ptr, "FILE LIST:", len, 0)) == NULL) {
  146         endptr = fullfile + strlen(fullfile);
  147     }
  148     while ((ptr = pstrnstr(ptr, hdr, len - (ptr - fullfile), 0)) != NULL) {
  149         if (ptr >= endptr) { return NULL; }
  150         if (ptr != fullfile) {
  151             if (*(ptr-1) != '\n') {
  152                 ptr++;
  153                 continue;
  154             }
  155         }
  156         
  157         // This one is handled differently. And FILE LIST has to be handled in body.
  158         ptr += strlen(hdr);
  159         
  160         // Any empty space but newline
  161         while ((isspace(*ptr)) && (*ptr != '\n')) {
  162             ptr++;
  163             if (ptr == endptr) { return NULL; }
  164         }
  165         
  166         // This kid is from a different town.
  167         if (!strcmp("PACKAGE DESCRIPTION:", hdr)) {
  168             if (*ptr != '\n') { return NULL; }
  169             ptr++;
  170             if ((!strncmp("FILE LIST:", ptr, 10)) || (!strncmp("PACKAGE ", ptr, 8)) || (!strncmp("COMPRESSED ", ptr, 11)) || (!strncmp("UNCOMPRESSED ", ptr, 13))) {
  171                 return NULL;
  172             }
  173         }
  174         if ((end = strchr(ptr, '\n')) == NULL) { end = endptr; }
  175         return strndup(ptr, end-ptr);
  176         ptr++;
  177     }
  178     return NULL;
  179 }
  180 
  181 // INFILTER()
  182 //
  183 // Filters out hidden files.
  184 //
  185 // Parameters:
  186 //   pointer to dirent structure, containing match
  187 //
  188 // Return value:
  189 //   zero if not matching
  190 //   non-zero if match
  191 static int infilter(const struct dirent *inname) {
  192     return (inname->d_name[0] != '.');
  193 }
  194 
  195 // PARSESLACKNAME()
  196 //
  197 // Attempts to parse the package information from filename, expecting a given
  198 // filename format.
  199 //
  200 // Parameters:
  201 //   filename
  202 //   pointer to package info, to which data is written
  203 //
  204 // Return value:
  205 //   0 if no problem
  206 //   1 if troubles parsing the filename
  207 static int parseslackname(char *name, pkginfo *pinfo) {
  208     char        *parsed, *ptr;
  209     
  210     parsed = strdup(name);
  211     
  212     // strip off build
  213     if ((ptr = strrchr(parsed, '-')) == NULL) {
  214         free(parsed);
  215         return 1;
  216     }
  217     *ptr = '\0';
  218     
  219     // strip off arch
  220     if ((ptr = strrchr(parsed, '-')) == NULL) {
  221         free(parsed);
  222         return 1;
  223     }
  224     *ptr = '\0';
  225     
  226     // get version
  227     if ((ptr = strrchr(parsed, '-')) == NULL) {
  228         free(parsed);
  229         return 1;
  230     }
  231     *ptr = '\0';
  232     pinfo->version = strdup(ptr+1);
  233     pinfo->name = strdup(parsed);
  234     
  235     free(parsed);
  236     return 0;
  237 }
  238 
  239 // ENSUREDATA()
  240 //
  241 // Ensures there is some basic package information about the package, no matter
  242 // what happens.
  243 //
  244 // Parameters:
  245 //   the filename
  246 //   pointer package info, to which data is written
  247 //
  248 // Return value:
  249 //   void
  250 static void ensuredata(char *fname, pkginfo *pinfo) {
  251     char *eptr, *fptr;
  252     
  253     if (pinfo->name == NULL) {
  254         eptr = fname + strlen(fname);
  255         
  256         fptr = fname;
  257         while ((fptr < eptr)) {
  258             if ((isdigit(*fptr)) && (fptr > fname)) {
  259                 if (*(fptr-1) == '-') {
  260                     fptr--;
  261                     break;
  262                 }
  263             }
  264             fptr++;
  265         }
  266         
  267         pinfo->name = strndup(fname, fptr-fname);
  268         if (pinfo->version == NULL) { 
  269             pinfo->version = strdup(fptr+1);
  270         }
  271     }
  272     
  273     if (pinfo->version == NULL) { pinfo->version = strdup("unknown"); }
  274     if (pinfo->description == NULL) { pinfo->description = strdup("Slackware package, no description."); }
  275 }
  276 
  277 #ifdef SLACK_COMPLEX
  278 ///////////////////////////////////////////////////////////////////////////////
  279 //                                                                           //
  280 // C O M P L E X   S H E L L   S E M I P A R S I N G                         //
  281 //                                                                           //
  282 ///////////////////////////////////////////////////////////////////////////////
  283 
  284 // SWITCH_NODATA_OPTIONS()
  285 //
  286 // Checks if needle is a flag, which takes no additional data, as defined in fdef.
  287 //
  288 // Parameters:
  289 //   needle
  290 //   pointer to function definition
  291 //
  292 // Return value:
  293 //   0 if no match
  294 //   id of the flag otherwise
  295 int switch_nodata_options(char *ptr, funcdef *fdef) {
  296     unsigned long   i;
  297     
  298     for (i=0; i < fdef->flagcount; i++) {
  299         if (fdef->flags[i].data == NODATA) {
  300             if (!strcmp(ptr, fdef->flags[i].flag)) {
  301                 return i+1;
  302             }
  303         }
  304     }
  305     
  306     return 0;
  307 }
  308 
  309 // SWITCH_DATA_OPTIONS()
  310 //
  311 // Checks if needle is a flag, which takes some additional data, as defined in fdef.
  312 //
  313 // Parameters:
  314 //   needle
  315 //   pointer to function definition
  316 //
  317 // Return value:
  318 //   0 if no match
  319 //   id of the flag otherwise
  320 int switch_data_options(char *ptr, funcdef *fdef) {
  321     unsigned long   i;
  322     
  323     for (i=0; i < fdef->flagcount; i++) {
  324         if (fdef->flags[i].data == SPACEDATA) {
  325             if (!strcmp(ptr, fdef->flags[i].flag)) {  return i+1; }
  326         }
  327         if (fdef->flags[i].data == EQUIDATA) {
  328             if (!strncmp(ptr, fdef->flags[i].flag, fdef->flags[i].flaglen)) {  return i+1; }
  329         }
  330     }
  331     
  332     return 0;
  333 }
  334 
  335 // counts on shortops grouped are oneletter ... but what else would they be?
  336 // SEPARATE_SHORTOPTS()
  337 //
  338 // Separates grouped short options, only last may take option
  339 //
  340 // Parameters:
  341 //   needle
  342 //   pointer to function definition
  343 //
  344 // Return value:
  345 //   0 if no match
  346 //   1 if one or more matches
  347 //   -1 if one or more matches, while the last takes data
  348 static int separate_shortopts(char *ptr, funcdef *fdef) {
  349     unsigned long   i;
  350     char        tmpbuf[3];
  351     int     reval, retval;
  352     
  353     ptr++;          // skip heading '-'
  354     
  355     tmpbuf[0] = '-';
  356     tmpbuf[2] = '\0';
  357     retval = 0;
  358     while (*ptr != '\0') {
  359         for (i=0; i < fdef->flagcount; i++) {
  360             if ((fdef->flags[i].type == SHORTOPT) && (fdef->flags[i].data == NODATA)) {
  361                 tmpbuf[1] = *ptr;
  362                 if (!strcmp(tmpbuf, fdef->flags[i].flag)) {
  363                     retval=1;
  364                     fdef->outputs[fdef->outcount].content = strdup("");
  365                     fdef->outputs[fdef->outcount].id = i;
  366                     fdef->outcount++;
  367                     fdef->outputs = realloc(fdef->outputs, sizeof(outformat) * (fdef->outcount + 1));
  368                 }
  369             }
  370         }
  371         ptr++;
  372     }
  373     
  374     if ((reval = switch_data_options(tmpbuf, fdef)) != 0) {
  375         return reval;
  376     } else {
  377         return -retval;
  378     }
  379 }
  380 
  381 // ADDCHAR()
  382 //
  383 // Adds a character to a buffer sized len, enlarges it by one char
  384 //
  385 // Parameters:
  386 //   pointer to (pointer to) the buffer
  387 //   size of buffer
  388 //   character added
  389 //
  390 // Return value:
  391 //   new size of buffer
  392 static unsigned long addchar(char **buf, unsigned long len, unsigned long *pos, char c) {
  393     if (len <= *pos) {
  394         len = *pos * 2;
  395         *buf = realloc(*buf, len + 1);
  396     }
  397     (*buf)[*pos] = c;
  398     (*pos)++;
  399     return len;
  400 }
  401 
  402 // ADDOUTPUT()
  403 //
  404 // Adds another data parameter.
  405 //
  406 // Parameters:
  407 //   pointer to function definition
  408 //   string added
  409 //   type of data
  410 //
  411 // Return value:
  412 //   none
  413 static void addoutput(funcdef *fdef, char *s, int type) {
  414     fdef->outputs[fdef->outcount].content = strdup(s);
  415     fdef->outputs[fdef->outcount].id = type;
  416     fdef->outcount++;
  417     fdef->outputs = realloc(fdef->outputs, sizeof(outformat) * (fdef->outcount + 1));
  418 }
  419 
  420 // PARSECOMMAND()
  421 //
  422 // A rather complex function, which parses the whole function call more or less
  423 // like POSIX compliant shell would. It's black magic, fear and tremble.
  424 //
  425 // Parameters:
  426 //   string we parse
  427 //   pointer which sets the end of string
  428 //   pointer to pointer to end of parsing
  429 //   pointer to function definition for which we parse
  430 //
  431 // Return value:
  432 //   always 0
  433 static int parsecommand(char *ptr, char *eptr, char **fptr, funcdef *fdef) {    
  434     int     pstatus, qstatus, ctype;
  435     // pstatus tells us about how parsing goes
  436     // qstatus is for data and tells us status of quotes
  437     // ctype contains information about data type, -2 uninteresting, -1 data, 0+ flag
  438     
  439     unsigned long   curlen, curpos;
  440     int     reval;
  441     char        *buf;
  442     
  443     ptr += strlen(fdef->fbase); // skip "ln"
  444     while ((isspace(*ptr)) && (*ptr != '\0')  && (*ptr != '\n')) {
  445         ptr++;                  // We can't have "ln--flag", we have to separate it ... by a freespace;
  446     }
  447     *fptr = ptr;
  448     
  449     pstatus = DATA;
  450     qstatus = QNONE;
  451     
  452     curlen = 0;
  453     curpos = 0;
  454     buf = malloc(1);
  455     
  456     ctype = -1;
  457     
  458     while (*ptr != '\0') {
  459         switch (*ptr) {
  460             case '\\':
  461                 switch (qstatus) {
  462                     case QNONE:
  463                         ptr++;
  464                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  465                         break;
  466                     case QSINGLE:
  467                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  468                         break;
  469                     case QDOUBLE:
  470                         ptr++;
  471                         switch (*ptr) {
  472                             case 'a':   curlen = addchar(&buf, curlen, &curpos, '\a');
  473                                 break;
  474                             case 'b':   curlen = addchar(&buf, curlen, &curpos, '\b');
  475                                 break;
  476                             case 'f':   curlen = addchar(&buf, curlen, &curpos, '\f');
  477                                 break;
  478                             case 'n':   curlen = addchar(&buf, curlen, &curpos, '\n');
  479                                 break;
  480                             case 'r':   curlen = addchar(&buf, curlen, &curpos, '\r');
  481                                 break;
  482                             case 't':   curlen = addchar(&buf, curlen, &curpos, '\t');
  483                                 break;
  484                             case 'v':   curlen = addchar(&buf, curlen, &curpos, '\v');
  485                                 break;
  486                             default: 
  487                                 curlen = addchar(&buf, curlen, &curpos, *ptr);
  488                                 break;
  489                         }
  490                         break;
  491                 }
  492                 break;
  493             case '\'':
  494                 switch (qstatus) {
  495                     case QNONE:
  496                         qstatus = QSINGLE;
  497                         break;
  498                     case QSINGLE:
  499                         qstatus = QNONE;
  500                         break;
  501                     case QDOUBLE:
  502                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  503                         break;
  504                 }
  505                 break;
  506             case '"':
  507                 switch (qstatus) {
  508                     case QNONE:
  509                         qstatus = QDOUBLE;
  510                         break;
  511                     case QSINGLE:
  512                         curlen = addchar(&buf, curlen, &curpos, *ptr);
  513                         break;
  514                     case QDOUBLE:
  515                         qstatus = QNONE;
  516                         break;
  517                 }
  518                 break;
  519             case '\t':
  520             case ' ':
  521                 if (qstatus == QNONE) {     // Terminate, we found end of data  
  522                     curlen = addchar(&buf, curlen, &curpos, '\0');
  523                     if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  524                         pstatus = PNOFLAG; 
  525                     } else {
  526                         if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  527                             ctype = reval-1;
  528                             if (fdef->flags[ctype].data == EQUIDATA) {                                      
  529                                 addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  530                                 ctype = -1;
  531                             }
  532                         } else {
  533                             if (ctype != -1) {
  534                                 addoutput(fdef, buf, ctype);
  535                                 ctype = -1;
  536                             } else {
  537                                 if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  538                                     ctype = reval-1;
  539                                     addoutput(fdef, "", ctype);
  540                                     ctype = -1;
  541                                 } else {
  542                                     if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  543                                         reval = separate_shortopts(buf, fdef);
  544                                         if (reval > 0) {
  545                                             ctype = reval - 1;
  546                                         } else { 
  547                                             ctype = -1;
  548 
  549                                             if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  550                                                 addoutput(fdef, buf, ctype);
  551                                             }
  552                                         }
  553                                     } else {
  554                                         ctype = -1;
  555                                         if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  556                                             addoutput(fdef, buf, ctype);
  557                                         }
  558                                     }
  559                                 }
  560                             }
  561                         }
  562                     }
  563                     
  564                     curlen = 0;
  565                     curpos = 0;
  566                     buf = realloc(buf, 1);
  567                     
  568                     pstatus = PNONE | (pstatus & PNOFLAG);
  569                     
  570                     while ((!isspace(*ptr)) && (ptr < eptr)) {
  571                         ptr++;
  572                     }
  573                 } else {                        // continue
  574                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  575                 }
  576                 break;
  577             case '&':
  578                 if (*(ptr+1) != '&') {
  579                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  580                     break;
  581                 } else {
  582                     free(buf);
  583                     ptr--;
  584                     *fptr = ptr;
  585                     return 0;
  586                 }
  587             case '|':
  588                 if (*(ptr+1) != '|') {
  589                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  590                     break;
  591                 } else {
  592                     free(buf);
  593                     ptr--;
  594                     *fptr = ptr;
  595                     return 0;
  596                 }
  597             case '\0':      // To ensure this is parsed fine...
  598                 qstatus = QNONE;
  599             case '`':       // This is questionable
  600             case ')':       // So are the subshells
  601             case '(':       // On the other hand, this
  602             case '}':       // is still meant to be rather
  603             case '{':       // simple parser, so it shouldn't
  604             case ';':       // matter much.
  605             case '\n':      // newline, on the other hand, is mandatory
  606                 if (qstatus == QNONE) {
  607                     curlen = addchar(&buf, curlen, &curpos, '\0');
  608                     
  609                     if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  610                         pstatus = PNOFLAG; 
  611                     } else {
  612                         if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  613                             ctype = reval-1;
  614                             if (fdef->flags[ctype].data == EQUIDATA) {                                      
  615                                 addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  616                                 ctype = -1;
  617                             }
  618                         } else {
  619                             if (ctype != -1) {
  620                                 addoutput(fdef, buf, ctype);
  621                                 ctype = -1;
  622                             } else {
  623                                 if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  624                                     ctype = reval-1;
  625                                     addoutput(fdef, "", ctype);
  626                                     ctype = -1;
  627                                 } else {
  628                                     if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  629                                         reval = separate_shortopts(buf, fdef);
  630                                         if (reval > 0) {
  631                                             ctype = reval - 1;
  632                                         } else { 
  633                                             ctype = -1;
  634                                             if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  635                                                 addoutput(fdef, buf, ctype);
  636                                             }
  637                                         }
  638                                     } else {
  639                                         ctype = -1;
  640                                         if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  641                                             addoutput(fdef, buf, ctype);
  642                                         }
  643                                     }
  644                                 }
  645                             }
  646                         }
  647                     }
  648                     
  649                     // We've reached end of function, let's drop out.
  650                     free(buf);
  651                     ptr--;  // not to waste the character we currently consider terminating -- it may be parsed outside
  652                     *fptr = ptr;
  653                     return 0;
  654                     // And drop out we did.
  655                 } else {
  656                     curlen = addchar(&buf, curlen, &curpos, *ptr);
  657                 }
  658                 break;
  659             default:
  660                 curlen = addchar(&buf, curlen, &curpos, *ptr);
  661                 break;
  662         }
  663         ptr++;
  664     }
  665     
  666     // cleanups
  667     if (curlen > 0) {
  668         curlen = addchar(&buf, curlen, &curpos, '\0');
  669         if ((pstatus != PNOFLAG) && (!strcmp(buf, "--"))) { 
  670             pstatus = PNOFLAG; 
  671         } else {
  672             if ((pstatus != PNOFLAG) && ((reval = switch_data_options(buf, fdef)) != 0)) {
  673                 ctype = reval-1;
  674                 if (fdef->flags[ctype].data == EQUIDATA) {                                      
  675                     addoutput(fdef, buf + fdef->flags[ctype].flaglen, ctype);
  676                     ctype = -1;
  677                 }
  678             } else {
  679                 if (ctype != -1) {
  680                     addoutput(fdef, buf, ctype);
  681                     ctype = -1;
  682                 } else {
  683                     if ((pstatus != PNOFLAG) && ((reval = switch_nodata_options(buf, fdef)) != 0)) {
  684                         ctype = reval-1;
  685                         addoutput(fdef, "", ctype);
  686                     } else {
  687                         if ((pstatus != PNOFLAG) && (strlen(buf)>=3) && (buf[0] == '-') && (buf[1] != '-'))  {
  688                             reval = separate_shortopts(buf, fdef);
  689                             if (reval > 0) {
  690                                 ctype = reval - 1;
  691                             } else { 
  692                                 ctype = -1;
  693                                 if (!((pstatus == PNOFLAG) && (buf[0] == '-')) && (reval == 0)) {
  694                                     addoutput(fdef, buf, ctype);
  695                                 }
  696                             }
  697                         } else {
  698                             ctype = -1;
  699                             if (!((pstatus == PNOFLAG) && (buf[0] == '-'))) {
  700                                 addoutput(fdef, buf, ctype);
  701                             }
  702                         }
  703                     }
  704                 }
  705             }
  706         }
  707     }
  708     
  709     *fptr = ptr;
  710 
  711     curlen = addchar(&buf, curlen, &curpos, '\0');
  712 
  713     free(buf);
  714     
  715     return 0;
  716 }
  717 
  718 // ADDFLAG()
  719 //
  720 // Adds another flag definition to function definition.
  721 //
  722 // Parameters:
  723 //   pointer to function definition
  724 //   flag added
  725 //   type of data obtained
  726 //   type (id) of flag
  727 //
  728 // Return value:
  729 //   none
  730 static void addflag(funcdef *fdef, char *flag, int data, int type) {
  731     fdef->flags[fdef->flagcount].flag = strdup(flag);
  732     fdef->flags[fdef->flagcount].flaglen = strlen(flag);
  733     fdef->flags[fdef->flagcount].data = data;
  734     fdef->flags[fdef->flagcount].type = type;
  735 
  736     fdef->flagcount++;
  737     fdef->flags = realloc(fdef->flags, sizeof(paramflag) * (fdef->flagcount + 1));
  738 }
  739 
  740 // FREEFUNCDEF()
  741 //
  742 // Frees the function definition members
  743 //
  744 // Parameters:
  745 //   pointer to function definition
  746 //
  747 // Return value:
  748 //   none
  749 static void freefuncdef(funcdef *fdef) {
  750     unsigned long   i;
  751     
  752     for (i=0; i<fdef->outcount; i++) {
  753         free(fdef->outputs[i].content);
  754     }
  755     for (i=0; i<fdef->flagcount; i++) {
  756         free(fdef->flags[i].flag);
  757     }
  758     
  759     free(fdef->fbase);
  760     
  761     free(fdef->flags);
  762     free(fdef->outputs);
  763 }
  764 
  765 // MATCHFUNCDEF()
  766 //
  767 // Matches needle against function definition
  768 //
  769 // Parameters:
  770 //   pointer to function definition
  771 //   needle
  772 //   number of functions in fdefs array
  773 //
  774 // Return value:
  775 //   -1 if no match
  776 //   index of function matching otherwise
  777 static int matchfuncdef(funcdef *fdefs, char *needle, unsigned long count) {
  778     unsigned long   i;
  779     for (i=0; i<count; i++) {
  780         if (!strcmp(needle, fdefs[i].fbase)) {
  781             return i;
  782         }
  783     }
  784     return -1;
  785 }
  786 
  787 // GETFUNCDATA()
  788 //
  789 // Dumps the content of n-th data member of a particular type in the function
  790 // definition
  791 //
  792 // Parameters:
  793 //   pointer to function definition
  794 //   needle
  795 //   number of functions in fdefs array
  796 //
  797 // Return value:
  798 //   -1 if no match
  799 //   index of function matching otherwise
  800 static char *getfuncdata(funcdef *fdef, unsigned long count, int type) {
  801     unsigned long   i, j;
  802     char        *reval;
  803     
  804     for (i=0, j=0; i<fdef->outcount; i++) {
  805         if (fdef->outputs[i].id == type) { 
  806             if (j++ == count) {
  807                 reval = strdup(fdef->outputs[i].content);
  808                 return reval;
  809             }
  810         }
  811     }
  812     return NULL;
  813 }
  814 
  815 // CLEARFUNCDATA()
  816 //
  817 // Frees and clears the data in the function definition, not the function
  818 // definition itself.
  819 //
  820 // Parameters:
  821 //   pointer to function definition
  822 //
  823 // Return value:
  824 //   none
  825 static void clearfuncdata(funcdef *fdef) {
  826     unsigned long   i;
  827     
  828     for (i=0; i<fdef->outcount; i++) {
  829         free(fdef->outputs[i].content);
  830     }
  831     fdef->outcount = 0;
  832     fdef->outputs = realloc(fdef->outputs, sizeof(outformat));
  833 }
  834 
  835 // ADDSHELLBUILTIN()
  836 //
  837 // Adds another shell builtin that doesn't take a parameter, which are handled
  838 // with extra care.
  839 //
  840 // Parameters:
  841 //   pointer to shell builtins array
  842 //   name of the builtin
  843 //
  844 // Return value:
  845 //   none
  846 static void addshellbuiltin(shellbuiltins *shbin, char *name) {
  847     shbin->names[shbin->count] = strdup(name);
  848     shbin->count++;
  849     shbin->names = realloc(shbin->names, (sizeof(char*)) * (shbin->count + 1));
  850 }
  851 
  852 // FREESHELLBUILTINS()
  853 //
  854 // Frees the shell builtins members
  855 //
  856 // Parameters:
  857 //   pointer to shell builtins
  858 //
  859 // Return value:
  860 //   none
  861 static void freeshellbuiltins(shellbuiltins *shbin) {
  862     unsigned long   i;
  863     
  864     for (i=0; i<shbin->count; i++) {
  865         free(shbin->names[i]);
  866     }
  867     free(shbin->names);
  868 }
  869 
  870 // ISSHELLBUILTIN()
  871 //
  872 // Checks if the name is a known shell builtin or no
  873 //
  874 // Parameters:
  875 //   pointer to shell builtins
  876 //   needle
  877 //
  878 // Return value:
  879 //   0 if not matched
  880 //   1 if matched
  881 static int isshellbuiltin(shellbuiltins *shbin, char *name) {
  882     unsigned long   i;
  883     
  884     for (i=0; i<shbin->count; i++) {
  885         if (!strcmp(name, shbin->names[i])) { return 1; }
  886     }
  887     return 0;
  888 }
  889 
  890 // CLEARUPSSHELLS()
  891 //
  892 // Clears up bogus subshells.
  893 //
  894 // Parameters:
  895 //   pointer to subshell array
  896 //   depth of subshell
  897 //
  898 // Return value:
  899 //   none
  900 static void clearupsshells(subshell *shell, int subdepth) {
  901     while (subdepth > 0) {
  902         free(shell[subdepth--].pwd);
  903     }
  904     free(shell[0].pwd);
  905 }
  906 
  907 
  908 // PARSEDOINST()
  909 //
  910 // Parses the doinst.sh script. This is the complex one, black magic, weird
  911 // code, hopes and prayers.
  912 //
  913 // Parameters:
  914 //   the parsed doinst.sh
  915 //   destination directory (viz pdef.ddir)
  916 //   pointer to package info where we write data
  917 //
  918 // Return value:
  919 //   0, always
  920 static int parsedoinst(char *line, char *ddir, pkginfo *pinfo) {
  921     char        *ptr, *rptr, *eptr, *fptr, *tmp, *tmp2, *tmp3;
  922     funcdef     *fdef;
  923     unsigned long   handfuncount, i;
  924     shellbuiltins   shbin;
  925     
  926     int     reval;
  927     int     subdepth, subbottom;
  928     int     qstatus, pstatus, sstatus;
  929     // qstatus controls status of ` subshells
  930     // pstatus controls status of parsing, since
  931     // we want some stuff sequentional
  932     // status tells us if we are going strictly
  933     // for slackware-likes or no
  934     // this counts for ifs, fors and cases
  935     
  936     subshell    *shell;
  937     
  938     ///////////////////////////////////////////////
  939     // Here is definition of shell builtins that //
  940     // do not take any parameter at all.         //
  941     ///////////////////////////////////////////////
  942     shbin.count = 0;
  943     shbin.names = malloc(sizeof(char*));
  944     addshellbuiltin(&shbin, "then");
  945     addshellbuiltin(&shbin, "else");
  946     addshellbuiltin(&shbin, "do");
  947     addshellbuiltin(&shbin, ":");
  948     addshellbuiltin(&shbin, "&&");
  949     addshellbuiltin(&shbin, "||");
  950     ///////////////////////////////////////////////
  951     // End of the definition part                //
  952     ///////////////////////////////////////////////
  953     
  954     handfuncount = 4;
  955     fdef = malloc(sizeof(funcdef) * handfuncount);
  956     ///////////////////////////////////////////////
  957     // Here is definition of function LN and the //
  958     // parameters that interest us               //
  959     ///////////////////////////////////////////////
  960     fdef[0].fbase = strdup("ln");
  961     fdef[0].outcount = 0;
  962     fdef[0].outputs = malloc(sizeof(outformat));
  963     fdef[0].flagcount = 0;
  964     fdef[0].flags = malloc(sizeof(paramflag));
  965     
  966     addflag(&fdef[0], "-S", SPACEDATA, SHORTOPT);               //0
  967     addflag(&fdef[0], "--suffix=", EQUIDATA, LONGOPT);          //1
  968     addflag(&fdef[0], "--backup=", EQUIDATA, LONGOPT);          //2
  969     addflag(&fdef[0], "--backup", NODATA, LONGOPT);             //3
  970     addflag(&fdef[0], "-b", NODATA, SHORTOPT);                  //4
  971     addflag(&fdef[0], "-s", NODATA, SHORTOPT);                  //5
  972     addflag(&fdef[0], "-f", NODATA, SHORTOPT);                  //6
  973     addflag(&fdef[0], "--force", NODATA, LONGOPT);              //7
  974     addflag(&fdef[0], "--target-directory=", EQUIDATA, LONGOPT);    //8
  975     addflag(&fdef[0], "--verbose", NODATA, LONGOPT);                //9
  976     addflag(&fdef[0], "-v", NODATA, SHORTOPT);                  //10
  977     addflag(&fdef[0], "--help", NODATA, LONGOPT);                   //11
  978     addflag(&fdef[0], "--version", NODATA, LONGOPT);                //12
  979     addflag(&fdef[0], "--interactive", NODATA, LONGOPT);            //13
  980     addflag(&fdef[0], "--symbolic", NODATA, LONGOPT);               //14
  981     addflag(&fdef[0], "--no-dereference", NODATA, LONGOPT);     //15
  982     addflag(&fdef[0], "--directory", NODATA, LONGOPT);              //16
  983     addflag(&fdef[0], "-i", NODATA, SHORTOPT);                  //17
  984     addflag(&fdef[0], "-F", NODATA, SHORTOPT);                  //18
  985     addflag(&fdef[0], "-d", NODATA, SHORTOPT);                  //19
  986     ///////////////////////////////////////////////
  987     // End of the definition part                //
  988     ///////////////////////////////////////////////
  989     
  990     ///////////////////////////////////////////////
  991     // Here is definition of function CD and the //
  992     // parameters that interest us               //
  993     ///////////////////////////////////////////////
  994     fdef[1].fbase = strdup("cd");
  995     fdef[1].outcount = 0;
  996     fdef[1].outputs = malloc(sizeof(outformat));
  997     fdef[1].flagcount = 0;
  998     fdef[1].flags = malloc(sizeof(paramflag));
  999     
 1000     addflag(&fdef[1], "-L", SPACEDATA, SHORTOPT);
 1001     addflag(&fdef[1], "-P", SPACEDATA, SHORTOPT);
 1002     ///////////////////////////////////////////////
 1003     // End of the definition part                //
 1004     ///////////////////////////////////////////////
 1005     
 1006     ///////////////////////////////////////////////
 1007     // Here is definition of remove functinon    //
 1008     ///////////////////////////////////////////////
 1009     fdef[2].fbase = strdup("rm");
 1010     fdef[2].outcount = 0;
 1011     fdef[2].outputs = malloc(sizeof(outformat));
 1012     fdef[2].flagcount = 0;
 1013     fdef[2].flags = malloc(sizeof(paramflag));
 1014     
 1015     addflag(&fdef[2], "-d", NODATA, SHORTOPT);
 1016     addflag(&fdef[2], "-f", NODATA, SHORTOPT);
 1017     addflag(&fdef[2], "-i", NODATA, SHORTOPT);
 1018     addflag(&fdef[2], "-r", NODATA, SHORTOPT);
 1019     addflag(&fdef[2], "-R", NODATA, SHORTOPT);
 1020     addflag(&fdef[2], "-v", NODATA, SHORTOPT);
 1021     addflag(&fdef[2], "--directory", NODATA, LONGOPT);
 1022     addflag(&fdef[2], "--force", NODATA, LONGOPT);
 1023     addflag(&fdef[2], "--interactive", NODATA, LONGOPT);
 1024     addflag(&fdef[2], "--no-preserve-root", NODATA, LONGOPT);
 1025     addflag(&fdef[2], "--preserve-root", NODATA, LONGOPT);
 1026     addflag(&fdef[2], "--verbose", NODATA, LONGOPT);
 1027     addflag(&fdef[2], "--help", NODATA, LONGOPT);
 1028     addflag(&fdef[2], "--version", NODATA, LONGOPT);
 1029     ///////////////////////////////////////////////
 1030     // End of the definition part                //
 1031     ///////////////////////////////////////////////
 1032     
 1033     ///////////////////////////////////////////////
 1034     // Here is definition of temp functinon,     //
 1035     // this is a restplace for any function not  //
 1036     // matching any previous one.                //
 1037     ///////////////////////////////////////////////
 1038     fdef[3].fbase = strdup("");
 1039     fdef[3].outcount = 0;
 1040     fdef[3].outputs = malloc(sizeof(outformat));
 1041     fdef[3].flagcount = 0;
 1042     fdef[3].flags = malloc(sizeof(paramflag));
 1043     ///////////////////////////////////////////////
 1044     // End of the definition part                //
 1045     ///////////////////////////////////////////////
 1046     
 1047     subdepth = 0;
 1048     subbottom = 0;
 1049     qstatus = QNONE;
 1050     pstatus = 0;
 1051     sstatus = 0;
 1052     shell = malloc(sizeof(subshell));
 1053     shell[0].pwd = strdup("/");         // We are not going to absolutize yet.
 1054     shell[0].status = SBLOCK;           // This is a hack which prevents segfaults if some code eventually breaks the handling;
 1055     
 1056     ptr = line;
 1057     eptr = line + strlen(line);
 1058     
 1059     ptr = line;
 1060     
 1061     while (*ptr != '\0') {
 1062         switch (*ptr) {
 1063             case '#':
 1064                     while ((*ptr != '\n') && (*ptr != '\0')) {
 1065                         ptr++;
 1066                     }
 1067                 break;
 1068             case '\\':
 1069                 ptr++;
 1070                 break;
 1071             
 1072             case ' ':
 1073             case ';':
 1074             case '\t':
 1075             case '\n':
 1076                 if (sstatus == 2) { sstatus = 0; }
 1077                 break;
 1078             
 1079             case '{':
 1080             case '(':
 1081                 //pstatus = 1;  // We check for ( cd /foo ; ln -sf foo bar ) or .. rm -rf foo )
 1082                 switch (pstatus) {
 1083                     case 0:
 1084                     case 4:
 1085                         pstatus++;
 1086                         break;
 1087                     default:
 1088                         pstatus = 0;
 1089                         break;
 1090                 }
 1091                 
 1092                 subdepth++;
 1093                 shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1094                 shell[subdepth].pwd = strdup(shell[subdepth-1].pwd);
 1095                 shell[subdepth].status = SCLEAR;
 1096                 break;
 1097             case ')':
 1098             case '}':
 1099                 if (shell[subdepth].status == SCLEAR) {
 1100                     switch (pstatus) {
 1101                         case 7:
 1102                             pstatus = 0;
 1103                             ///////////////////////
 1104                             // Nasty tmp mess    //
 1105                             ///////////////////////
 1106                             tmp2 = getfuncdata(&fdef[2], 0, -1);
 1107                             if (tmp2 != NULL) {                             
 1108                                 tmp = getfuncdata(&fdef[0], 1, -1);
 1109                                 if (tmp != NULL) {
 1110                                     if (!strcmp(tmp2, tmp)) {
 1111                                         // More or less slack way, how about if it is a -symbolic- link?
 1112                                         if ((tmp3 = getfuncdata(&fdef[0], 0, 5)) != NULL) {
 1113                                             free(tmp3);
 1114                                             
 1115                                             addfile(pinfo, absolutizestr(tmp2, shell[subdepth].pwd), F_IRRELEVANT);
 1116                                         }
 1117                                         else if ((tmp3 = getfuncdata(&fdef[0], 0, 14)) != NULL) {
 1118                                             free(tmp3);
 1119                                             
 1120                                             addfile(pinfo, absolutizestr(tmp2, shell[subdepth].pwd), F_IRRELEVANT);
 1121                                         }
 1122                                         free(tmp);
 1123                                     } else {
 1124                                         free(tmp);
 1125                                     }
 1126                                     
 1127                                     free(tmp2);
 1128                                 } else {
 1129                                     free(tmp2);
 1130                                 }
 1131                             }
 1132                             break;
 1133                         case 3:
 1134                             pstatus ++;
 1135                             break;
 1136                         default:
 1137                             pstatus = 0;
 1138                         break;
 1139                     }
 1140 
 1141                     free(shell[subdepth].pwd);
 1142                     subdepth--;
 1143                     shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1144                 }
 1145                 break;
 1146             case '`':
 1147                 switch (qstatus) {
 1148                     case QNONE: 
 1149                         qstatus = QSUBSHELL;
 1150                         subdepth++;
 1151                         shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1152                         shell[subdepth].pwd = strdup(shell[subdepth-1].pwd);
 1153                         break;
 1154                     case QSUBSHELL:
 1155                         qstatus = QNONE;
 1156                         free(shell[subdepth].pwd);
 1157                         subdepth--;
 1158                         shell = realloc(shell, sizeof(subshell) * (subdepth+1));
 1159                         break;
 1160                 }
 1161                 break;
 1162             
 1163             default:
 1164                 rptr = ptr;
 1165                 
 1166                 while ((!isspace(*rptr)) && (*rptr != ';') && (*rptr != '(') && (*rptr != ')') && (*rptr != '{') && (*rptr != '}') && (*rptr != '\0')) {
 1167                     rptr++;
 1168                 }
 1169                 
 1170                 fptr = rptr;
 1171                 tmp = strndup(ptr, rptr - ptr);
 1172                 
 1173                 reval = matchfuncdef(fdef, tmp, 3);
 1174                 if (reval == -1) { reval = 3; free(fdef[reval].fbase); fdef[reval].fbase=strdup(tmp); }
 1175                 clearfuncdata(&fdef[reval]);
 1176                 
 1177                 if (!isshellbuiltin(&shbin, tmp)) {
 1178                     parsecommand(ptr, eptr, &fptr, &fdef[reval]);
 1179                 }
 1180                 free(tmp);              
 1181 
 1182                 ptr = fptr;
 1183                 switch (reval) {
 1184                     case 0: // symlink
 1185                         tmp2 = getfuncdata(&fdef[reval], 0, -1);
 1186                         
 1187                         if (tmp != NULL) {
 1188                             tmp = getfuncdata(&fdef[reval], 1, -1);
 1189                             if ((tmp != NULL)&&(*tmp != '\0')) {
 1190                                 if (pstatus == 6) { 
 1191                                     pstatus++; 
 1192                                 } else { 
 1193                                     pstatus = 0; 
 1194                                     if (sstatus == 0) {
 1195                                         addfile(pinfo, absolutizestr(tmp, shell[subdepth].pwd), F_IRRELEVANT);
 1196                                     } // else protected and we don't do any other than what removepkg would see
 1197                                 }
 1198                                 free(tmp);
 1199                             } else {
 1200                                 pstatus = 0;
 1201                             }
 1202                             free(tmp2);
 1203                         } else {
 1204                             pstatus = 0;
 1205                         }
 1206                         break;
 1207                     case 1: // cd
 1208                         tmp = getfuncdata(&fdef[reval], 0, -1);
 1209                     
 1210                         if ((pstatus == 1) || (pstatus == 5)) { pstatus ++; }
 1211                         
 1212                         if (tmp != NULL) {
 1213                             if (tmp[0] == '/') {
 1214                                 free(shell[subdepth].pwd);
 1215                                 shell[subdepth].pwd = strdup(tmp);
 1216                             } else {
 1217                                 free(shell[subdepth].pwd);
 1218                                 shell[subdepth].pwd = absolutizestr(tmp, shell[subdepth-1].pwd);
 1219                             }
 1220                             free(tmp);
 1221                         }
 1222                         break;
 1223                     case 2: // rm
 1224                         tmp = getfuncdata(&fdef[reval], 0, -1);
 1225                         if (tmp != NULL) {
 1226                             if (pstatus == 2) { pstatus++; } else { pstatus = 0; }
 1227                             free(tmp);
 1228                         }
 1229                         break;
 1230                     default:                    
 1231                         pstatus = 0;
 1232                         if (!strcmp(fdef[reval].fbase, "case")) {
 1233                             shell[subdepth].status = SBLOCK;
 1234                             sstatus = 1;
 1235                         }
 1236                         if (!strcmp(fdef[reval].fbase, "esac")) {
 1237                             shell[subdepth].status = SCLEAR;
 1238                             sstatus = 0;
 1239                         }
 1240                         if ((!strcmp(fdef[reval].fbase, "&&")) || (!strcmp(fdef[reval].fbase, "||"))) {
 1241                             sstatus = 2;
 1242                         }
 1243                         
 1244                         if ((!strcmp(fdef[reval].fbase, "if")) || (!strcmp(fdef[reval].fbase, "do"))) {
 1245                             sstatus = 1;
 1246                         }
 1247                         
 1248                         if ((!strcmp(fdef[reval].fbase, "fi")) || (!strcmp(fdef[reval].fbase, "done"))) {
 1249                             sstatus = 0;
 1250                         }
 1251                         break;
 1252                 }
 1253 
 1254                 if (*ptr == '\0') {
 1255                     freeshellbuiltins(&shbin);
 1256                     for (i=0; i<handfuncount; i++) {
 1257                         freefuncdef(&fdef[i]);
 1258                     }
 1259                     free(fdef);
 1260                     
 1261                     clearupsshells(shell, subdepth);
 1262                     free(shell);
 1263                     return 0;
 1264                 }
 1265                 break;
 1266         }
 1267         ptr++;
 1268     }
 1269     
 1270     clearupsshells(shell, subdepth);
 1271     free(shell);
 1272     
 1273     freeshellbuiltins(&shbin);
 1274     
 1275     for (i=0; i<handfuncount; i++) {
 1276         freefuncdef(&fdef[i]);
 1277     }
 1278 
 1279     free(fdef);
 1280     
 1281     return 0;
 1282 }
 1283 #else
 1284 ///////////////////////////////////////////////////////////////////////////////
 1285 //                                                                           //
 1286 // T R I V I A L   S H E L L   S E M I P A R S I N G                         //
 1287 //                                                                           //
 1288 ///////////////////////////////////////////////////////////////////////////////
 1289 
 1290 
 1291 // FREELINKINFO()
 1292 //
 1293 // Frees information about a symlink
 1294 //
 1295 // Parameters:
 1296 //   pointer to linkinfo
 1297 //
 1298 // Return value:
 1299 //   none
 1300 static void freelinkinfo(linkinfo *tofree) {
 1301     if (tofree->linkfile != NULL) { free(tofree->linkfile); }
 1302     if (tofree->target != NULL) { free(tofree->target); }
 1303     free(tofree);
 1304 }
 1305 
 1306 // STRNCHR()
 1307 //
 1308 // Same as strchr, but never goes over len chars.
 1309 //
 1310 // Parameters:
 1311 //   string checked
 1312 //   needle character
 1313 //   size of buffer
 1314 //
 1315 // Return value:
 1316 //   pointer to first match of needle
 1317 //   NULL if not matched
 1318 static char *strnchr(char *s, int c, unsigned long len) {
 1319     char        *ptr;
 1320 
 1321     for (ptr = s; (char*)ptr < ((char*)s)+len; ptr++) {
 1322         if (*ptr == c) { return ptr; }
 1323     }
 1324     
 1325     return NULL;
 1326 }
 1327 
 1328 // CHECKFORCOMMENT()
 1329 //
 1330 // Checks if the given line contains comment.
 1331 //
 1332 // Parameters:
 1333 //   the line
 1334 //
 1335 // Return value:
 1336 //   0 if no comment
 1337 //   1 if comment
 1338 static int checkforcomment(char *line) {
 1339     char        *ptr;
 1340 
 1341     ptr = line;
 1342     while ((*ptr != '\n') && (*ptr != '\0')) {
 1343         if (*ptr == '#') {
 1344             *ptr = '\0';
 1345             return 1;
 1346         }
 1347         ptr++;
 1348     }
 1349     return 0;
 1350 }
 1351 
 1352 // READLINE()
 1353 //
 1354 // Reads a line from given source
 1355 //
 1356 // Parameters:
 1357 //   pointer to the line, it will be changed to sthe new line.
 1358 //   ending pointer
 1359 //
 1360 // Return value:
 1361 //   malloced line
 1362 static char *readline(char **ptr, char *eptr) {
 1363     char        *line, *hptr;
 1364 
 1365     do {
 1366         if ((hptr = strnchr(*ptr, '\n', eptr - *ptr)) == NULL) {
 1367             hptr = eptr;
 1368         }
 1369     } while (*(hptr-1) == '\\');
 1370     line = malloc(hptr - *ptr + 1);
 1371     strncpy(line, *ptr, hptr - *ptr);
 1372     line[hptr - *ptr] = '\0';
 1373     
 1374     *ptr = hptr + 1;
 1375     
 1376     return line;
 1377 }
 1378 
 1379 // LINETOLINK()
 1380 //
 1381 // Checks if the symlink is on the given line and if it is created slackware
 1382 // style. If so, it gives details about the symlink.
 1383 //
 1384 // Parameters:
 1385 //   line
 1386 //
 1387 // Return value:
 1388 //   pointer symlink information
 1389 //   NULL if not slackware symlink
 1390 static linkinfo *linetolink(char *line) {
 1391     char        *rptr, *rhptr, *tmp;        // these for reversing the script
 1392     linkinfo    *reval;
 1393     
 1394     reval = malloc(sizeof(linkinfo));
 1395     reval->linkfile = NULL;
 1396     reval->target = NULL;
 1397     
 1398     rptr = strstr(line, "( cd ");
 1399     if (rptr == NULL) { 
 1400         freelinkinfo(reval);
 1401         return NULL;
 1402     }
 1403 
 1404     rptr += 4;
 1405     *rptr = '/';    // We need a prefixing '/', and the previous data is of no interest
 1406     if ((rhptr = strstr(line, " ; ")) == NULL) { 
 1407         freelinkinfo(reval);
 1408         return NULL;
 1409     }
 1410     *rhptr = '\0';
 1411     
 1412     tmp = strdup(rptr);
 1413 
 1414     rhptr++;
 1415     if ((rptr = strstr(rhptr, "ln -sf")) == NULL) {
 1416         free(tmp);
 1417         freelinkinfo(reval);
 1418         return NULL;
 1419     }
 1420     
 1421     rptr += 7;
 1422 
 1423     if ((rhptr = strchr(rptr, ' ')) == NULL) {
 1424         free(tmp);
 1425         freelinkinfo(reval);
 1426         return NULL;
 1427     }
 1428     *rhptr = '\0';
 1429     
 1430     reval->target = strdup(rptr);
 1431 
 1432     rptr = rhptr+1;
 1433     
 1434     if ((rhptr = strchr(rptr, ' ')) == NULL) {
 1435         free(tmp);
 1436         freelinkinfo(reval);
 1437         return NULL;
 1438     }
 1439     *rhptr = '\0';
 1440 
 1441     if (*(rhptr+1) != ')') {
 1442         free(tmp);
 1443         freelinkinfo(reval);
 1444         return NULL;
 1445     }
 1446 
 1447     *rhptr = '\0';
 1448 
 1449     reval->linkfile = absolutizestr(rptr, tmp);
 1450     free(tmp);
 1451 
 1452     return reval;
 1453 }
 1454 
 1455 // LINETORM()
 1456 //
 1457 // Checks if the rm is on the given line and if it is created slackware
 1458 // style. If so, it gives details about the rm.
 1459 //
 1460 // Parameters:
 1461 //   line
 1462 //
 1463 // Return value:
 1464 //   file which would be removed
 1465 //   NULL if not slackware rm
 1466 static char *linetorm(char *line) {
 1467     char        *rptr, *rhptr, *reval, *tmp;        // these for reversing the script
 1468     
 1469     rptr = strstr(line, "( cd ");
 1470     if (rptr == NULL) {
 1471         return NULL;
 1472     }
 1473 
 1474     rptr += 4;
 1475     *rptr = '/';    // We need a prefixing '/', and the previous data is of no interest
 1476     if ((rhptr = strstr(line, " ; ")) == NULL) { 
 1477         return NULL;
 1478     }
 1479     *rhptr = '\0';
 1480     
 1481     tmp = strdup(rptr);
 1482 
 1483     rhptr++;
 1484     if ((rptr = strstr(rhptr, "rm -rf")) == NULL) {
 1485         free(tmp);
 1486         return NULL;
 1487     }
 1488     
 1489     rptr += 7;
 1490     
 1491     if ((rhptr = strrchr(rptr, ' ')) == NULL) {
 1492         free(tmp);
 1493         return NULL;
 1494     }
 1495     *rhptr = '\0';
 1496     
 1497     reval = absolutizestr(rptr, tmp);
 1498     free(tmp);
 1499 
 1500     if (*(rhptr+1) != ')') {
 1501         free(tmp);
 1502         free(reval);
 1503         return NULL;
 1504     }
 1505 
 1506     return reval;
 1507 }
 1508 
 1509 // PARSEDOINST()
 1510 //
 1511 // Parses the doinst.sh script. This is the trivial one, it only checks for
 1512 // those generated by the official slackware makepkg
 1513 //
 1514 // Parameters:
 1515 //   the parsed doinst.sh
 1516 //   destination directory (viz pdef.ddir)
 1517 //   pointer to package info where we write data
 1518 //
 1519 // Return value:
 1520 //   0, always
 1521 static int parsedoinst(char *fullfile, char *dirprefix, pkginfo *pinfo) {
 1522     char        *line, *oldline, *tmp, *tmpcomp, *processedline, *ptr;
 1523     linkinfo    *tstlink;
 1524     unsigned long   filesize;
 1525     
 1526     line = NULL;
 1527     filesize = strlen(fullfile);
 1528     
 1529     ptr = fullfile;
 1530     
 1531     do {
 1532         oldline = line;
 1533         line = readline(&ptr, fullfile + filesize);
 1534         checkforcomment(line);
 1535         if (*line != '\0') {
 1536             processedline=strdup(line); // We dup here instead of before checkforcomment, since we want comments lost anyway
 1537             if ((tstlink = linetolink(processedline)) != NULL) {
 1538                 if ((tmp = linetorm(oldline)) != NULL) {
 1539                     tmpcomp = absolutizestr(tmp, dirprefix);
 1540                     free(tmp);
 1541                     tmp = absolutizestr(tstlink->linkfile, dirprefix);
 1542                     
 1543                     if (!strcmp(tmp, tmpcomp)) {    // is the previous rm and the current ln the same?
 1544                         addfile(pinfo, strdup(tmp), F_IRRELEVANT);
 1545                     }
 1546                     
 1547                     free(tmpcomp);
 1548                     free(tmp);
 1549                 }
 1550                 freelinkinfo(tstlink);
 1551             }
 1552             free(processedline);
 1553         }
 1554         free(oldline);
 1555     } while((void*)ptr < (((void*)fullfile) + filesize));
 1556     free(line);
 1557     
 1558     return 0;
 1559 }
 1560 ///////////////////////////////////////////////////////////////////////////////
 1561 #endif
 1562 
 1563 ///////////////////////////////////////////////////////////////////////////////
 1564 //                                                                           //
 1565 // A P I   F U N C T I O N S                                                 //
 1566 //                                                                           //
 1567 ///////////////////////////////////////////////////////////////////////////////
 1568 
 1569 void *opendb(char *path) {
 1570     dbhandle    *reval;
 1571     char                *tmpfpath;
 1572     
 1573     tmpfpath = malloc(strlen(path) + 11);   // + 'packages/' + '/' + '\0'
 1574     strcpy(tmpfpath, path);
 1575     if (tmpfpath[strlen(tmpfpath)-1] != '/') { 
 1576         strcat(tmpfpath, "/");
 1577     }
 1578     strcat(tmpfpath, "packages/");
 1579     
 1580     reval = malloc(sizeof(dbhandle));
 1581     reval->fpath = strdup(path);
 1582     reval->curname = 0;
 1583     reval->namecount = scandir(tmpfpath, &reval->namelist, infilter, alphasort);
 1584     free(tmpfpath);
 1585     if (reval -> namecount <= 0) {
 1586         free(reval->fpath);
 1587         free(reval);
 1588         return NULL;
 1589     }
 1590     
 1591     return reval;
 1592 }
 1593 void rewinddb(void *handle) {
 1594     ((dbhandle*)handle)->curname = 0;
 1595 }
 1596 int iswriteable(void *handle) {
 1597     return 0;
 1598 }
 1599 int closedb(void *handle) {
 1600     long i;
 1601     for (i=0; i<((dbhandle*)handle)->namecount; i++) {
 1602         free(((dbhandle*)handle)->namelist[i]);
 1603     }
 1604     free(((dbhandle*)handle)->namelist);
 1605     free(((dbhandle*)handle)->fpath);
 1606     free(((dbhandle*)handle));
 1607     return 0;
 1608 }
 1609 int readpkg(void *handle, pkginfo *pinfo) {
 1610     struct stat     statbuf;
 1611     void                        *filemap;
 1612     int                         fd;
 1613     
 1614     char                        *buf, *sptr, *eptr;
 1615     
 1616     
 1617     if (((dbhandle*)handle)->curname >= ((dbhandle*)handle)->namecount) {
 1618         return 1;
 1619     }
 1620     
 1621     // The base control data
 1622     buf = malloc(strlen(((dbhandle*)handle)->fpath) + strlen(((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name) + 11);
 1623     buf = strcpy(buf, ((dbhandle*)handle)->fpath);
 1624     if (buf[strlen(((dbhandle*)handle)->fpath)-1] != '/') {
 1625         buf = strcat(buf, "/");
 1626     }
 1627     buf = strcat(buf, "packages/");
 1628     buf = strcat(buf, ((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name);
 1629     
 1630     if ((fd = open(buf, O_RDONLY)) == -1) { 
 1631         free(buf);
 1632         return 1; 
 1633     }
 1634     fstat(fd, &statbuf);
 1635     free(buf);
 1636     
 1637     
 1638     filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
 1639     if (filemap == MAP_FAILED) { return 1; }
 1640     
 1641     sptr = filemap;
 1642     
 1643     buf = getctrlhdr(filemap, "PACKAGE NAME:", statbuf.st_size);
 1644     parseslackname(buf, pinfo);
 1645     free(buf);
 1646     
 1647     if ((buf = getctrlhdr(filemap, "PACKAGE DESCRIPTION:", statbuf.st_size)) != NULL) {
 1648         sptr = buf;
 1649         eptr = buf + strlen(buf);
 1650         if ((sptr = strchr(buf, ':')) != NULL) {
 1651             if (sptr < eptr + 1) {
 1652                 sptr++;
 1653             }
 1654             while ((isspace(*sptr)) && (*sptr!= '\n') && (sptr < eptr)) {
 1655                 sptr++;
 1656             }
 1657             
 1658             pinfo->description = strdup(sptr);
 1659             if (pinfo->name == NULL) {
 1660                 *sptr = '\0';
 1661                 pinfo->name = strdup(buf);
 1662             }
 1663         } else {
 1664             pinfo->description = strdup(sptr);
 1665         }
 1666         free(buf);
 1667     } else {
 1668         pinfo->description = strdup("Slackware package, no description.");
 1669     }
 1670     
 1671     ensuredata(((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name, pinfo);
 1672     
 1673     sptr = pstrnstr(filemap, "FILE LIST:\n", statbuf.st_size, 0);
 1674 
 1675     if ((sptr == NULL) || ((sptr != filemap) && (*(sptr-1) != '\n'))) {
 1676         free(pinfo->name);
 1677         free(pinfo->version);
 1678         free(pinfo->description);
 1679         return 1;
 1680     }
 1681     
 1682     sptr += 11;
 1683     do {
 1684         eptr = strchr(sptr, '\n');
 1685         if (eptr == NULL) {
 1686             eptr = (char*)(filemap + statbuf.st_size);
 1687         }
 1688         buf = strndup(sptr, eptr - sptr);
 1689         addfile(pinfo, absolutizestr(buf, "/"), F_IRRELEVANT);
 1690         free(buf);
 1691         sptr = eptr + 1;
 1692     } while (sptr < (char*)(filemap + statbuf.st_size));
 1693     
 1694     munmap(filemap, statbuf.st_size);
 1695     close(fd);
 1696     
 1697     // Now the doinst.sh, acting as posinst -- we don't really mind if this
 1698     // fails.
 1699     buf = malloc(strlen(((dbhandle*)handle)->fpath) + strlen(((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name) + 10);
 1700     buf = strcpy(buf, ((dbhandle*)handle)->fpath);
 1701     if (buf[strlen(((dbhandle*)handle)->fpath)-1] != '/') {
 1702         buf = strcat(buf, "/");
 1703     }
 1704     buf = strcat(buf, "scripts/");
 1705     buf = strcat(buf, ((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name);
 1706     
 1707     if ((fd = open(buf, O_RDONLY)) != -1) { 
 1708         fstat(fd, &statbuf);
 1709         if (statbuf.st_size > 0) {
 1710             // It's senseless to attempt to load a file that's just empty
 1711             filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
 1712             if (filemap != MAP_FAILED) {
 1713                 pinfo->postinst.len = statbuf.st_size + 1;
 1714                 pinfo->postinst.data = malloc(pinfo->postinst.len);
 1715                 memcpy(pinfo->postinst.data, filemap, pinfo->postinst.len - 1);
 1716                 pinfo->postinst.data[pinfo->postinst.len - 1] = '\0';
 1717                 
 1718                 parsedoinst(pinfo->postinst.data, "/", pinfo);
 1719                 
 1720                 munmap(filemap, statbuf.st_size);
 1721             }
 1722         }
 1723         close(fd);
 1724     }
 1725     free(buf);
 1726     
 1727     ((dbhandle*)handle)->curname++;
 1728     
 1729     if (pinfo->postinst.data != NULL) {
 1730         // Installpkg passes this. Although no script really uses
 1731         // it, let's be nice.
 1732         pinfo->postinst.parameters[A_IRRELEVANT] = strdup("-install");
 1733     }
 1734     return 0;
 1735 }
 1736 int writepkg(void *handle, pkginfo *pinfo) {
 1737     return 1;
 1738 }
 1739 int delpkg(void *handle, char *pneedle) {
 1740     return 1;
 1741 }
 1742 int findpkg(void *handle, pkginfo needle, pkginfo *reval, int matchtype) {
 1743     char                            *ptr, *buf;
 1744     pkginfo                 tmppinfo;
 1745     unsigned long   i, j;
 1746     
 1747     while (((dbhandle*)handle)->curname < ((dbhandle*)handle)->namecount) {
 1748         if ((matchtype & MATCH_NAME) && (!(matchtype & MATCH_FILE))) {
 1749             buf = strdup(((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name);
 1750             
 1751             ptr = strrchr(buf, '-'); // build
 1752             if (ptr != NULL) {
 1753                 *ptr = '\0';
 1754                 ptr = strrchr(buf, '-'); // arch
 1755                 if (ptr != NULL) {
 1756                     *ptr = '\0';
 1757                     ptr = strrchr(buf, '-'); // version
 1758                     if (ptr != NULL) {
 1759                         *ptr = '\0';
 1760                     }
 1761                 }
 1762             }
 1763             
 1764             if (!fnmatch(needle.name, buf, 0)) {
 1765                 if (reval != NULL) { 
 1766                     if (readpkg(handle, reval)) {
 1767                         continue;
 1768                     }
 1769                 } else {
 1770                     ((dbhandle*)handle)->curname++;
 1771                 }
 1772                 
 1773                 if ((matchtype & MATCH_OVRWR) && (!strcmp(needle.name, buf))) {
 1774                     free(buf);
 1775                     return -1;
 1776                 } else {
 1777                     free(buf);
 1778                     return 1;
 1779                 }
 1780             }
 1781             free(buf);
 1782         } else if ((matchtype & MATCH_FILE) && (!(matchtype & MATCH_NAME))) {   
 1783             clearpinfo(&tmppinfo);
 1784             readpkg(handle, &tmppinfo);
 1785             for (i=0; i<needle.filecount; i++) {
 1786                 for (j=0; j<tmppinfo.filecount; j++) {
 1787                     // We do NOT want to match directories.
 1788                     if (needle.files[i].flag == F_DIRECTORY) continue;
 1789                     if (!fnmatch(needle.files[i].name, tmppinfo.files[j].name, 0)) {
 1790                         if (reval != NULL) {
 1791                             memcpy(reval, &tmppinfo, sizeof(pkginfo));
 1792                         }
 1793                         if ((matchtype & MATCH_OVRWR) && (!strcmp(needle.name, tmppinfo.name))){
 1794                             if (reval == NULL) {
 1795                                 freepinfo(&tmppinfo);
 1796                             }
 1797                             return -1;
 1798                         } else {
 1799                             if (reval == NULL) {
 1800                                 freepinfo(&tmppinfo);
 1801                             }
 1802                             return 1;
 1803                         }
 1804                     }
 1805                 }
 1806             }
 1807             freepinfo(&tmppinfo);
 1808         } else if ((matchtype & MATCH_NAME) && (matchtype & MATCH_FILE)) {
 1809             buf = strdup(((dbhandle*)handle)->namelist[((dbhandle*)handle)->curname]->d_name);
 1810             
 1811             ptr = strrchr(buf, '-'); // build
 1812             if (ptr != NULL) {
 1813                 *ptr = '\0';
 1814                 ptr = strrchr(buf, '-'); // arch
 1815                 if (ptr != NULL) {
 1816                     *ptr = '\0';
 1817                     ptr = strrchr(buf, '-'); // version
 1818                     if (ptr != NULL) {
 1819                         *ptr = '\0';
 1820                     }
 1821                 }
 1822             }
 1823             
 1824             clearpinfo(&tmppinfo);
 1825             readpkg(handle, &tmppinfo);
 1826             for (i=0; i<needle.filecount; i++) {
 1827                 for (j=0; j<tmppinfo.filecount; j++) {
 1828                     // We do NOT want to match directories.
 1829                     if (needle.files[i].flag == F_DIRECTORY) continue;
 1830                     if (!fnmatch(needle.files[i].name, tmppinfo.files[j].name, 0)) {
 1831                         if (reval != NULL) {
 1832                             memcpy(reval, &tmppinfo, sizeof(pkginfo));
 1833                         }
 1834                         if ((matchtype & MATCH_OVRWR) && (!strcmp(needle.name, tmppinfo.name))){
 1835                             if (reval == NULL) {
 1836                                 freepinfo(&tmppinfo);
 1837                             }
 1838                             return -1;
 1839                         } else {
 1840                             if (reval == NULL) {
 1841                                 freepinfo(&tmppinfo);
 1842                             }
 1843                             return 1;
 1844                         }
 1845                     }
 1846                 }
 1847             }
 1848             freepinfo(&tmppinfo);
 1849 
 1850             if (!fnmatch(needle.name, buf, 0)) {
 1851                 free(buf);
 1852             } else {
 1853                 free(buf);
 1854             }
 1855             break;
 1856         }
 1857         ((dbhandle*)handle)->curname++;
 1858     }
 1859     ((dbhandle*)handle)->curname = 0;
 1860     
 1861     return 0;
 1862 }