Main Page | Data Structures | File List | Data Fields | Globals

libuau.c

Go to the documentation of this file.
00001 /*
00002  * luau (Lib Update/Auto-Update): Simple Update Library
00003  * Copyright (C) 2003  David Eklund
00004  *
00005  * - This library is free software; you can redistribute it and/or             -
00006  * - modify it under the terms of the GNU Lesser General Public                -
00007  * - License as published by the Free Software Foundation; either              -
00008  * - version 2.1 of the License, or (at your option) any later version.        -
00009  * -                                                                           -
00010  * - This library is distributed in the hope that it will be useful,           -
00011  * - but WITHOUT ANY WARRANTY; without even the implied warranty of            -
00012  * - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         -
00013  * - Lesser General Public License for more details.                           -
00014  * -                                                                           -
00015  * - You should have received a copy of the GNU Lesser General Public          -
00016  * - License along with this library; if not, write to the Free Software       -
00017  * - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA -
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #  include <config.h>
00022 #endif
00023 
00024 #include <unistd.h>
00025 #include <sys/types.h>
00026 #include <sys/stat.h>
00027 #include <fcntl.h>
00028 #include <errno.h>
00029 #include <string.h>
00030 #include <math.h>
00031 #include <ctype.h>
00032 
00033 #include <glib.h>
00034 
00035 #include "libuau.h"
00036 #include "network.h"
00037 #include "error.h"
00038 #include "util.h"
00039 #include "install.h"
00040 #include "ftp.h"
00041 
00042 #ifdef WITH_DMALLOC
00043 #  include <dmalloc.h>
00044 #endif
00045 
00046 #ifdef WITH_LEAKBUG
00047 #  include <leakbug.h>
00048 #endif
00049 
00050 static int compareAlphaNumeric(const char *v1, const char *v2);
00051 
00052 static void categorizeUpdates(GPtrArray *updates, const AProgInfo *progInfo);
00053 static gboolean isIncompatible(AUpdate *update, const AProgInfo *progInfo);
00054 static gboolean isOld(AUpdate *update, const AProgInfo *progInfo);
00055 
00056 
00070 gboolean
00071 luau_getUpdateInfo(AUpdate *updateInfo, const char* updateID, const AProgInfo *progInfo) {
00072         GPtrArray *allUpdates = luau_checkForUpdates(progInfo);
00073         AUpdate *temp;
00074         gboolean found = FALSE;
00075         int i;
00076         
00077         for (i = 0; i < allUpdates->len; ++i) {
00078                 temp = g_ptr_array_index(allUpdates, i);
00079                 if (lutil_streq(temp->id, updateID)) {
00080                         luau_copyUpdate(updateInfo, temp);
00081                         found = TRUE;
00082                         break;
00083                 }
00084         }
00085         luau_freeUpdateArray(allUpdates);
00086         
00087         return found;
00088 }
00089 
00100 GPtrArray *
00101 luau_checkForUpdates(const AProgInfo *info) {
00102         GPtrArray *result;
00103         
00104         DBUGOUT("Checking for updates for %s: %s", info->id, info->url);
00105         result = luau_net_queryServer(info);
00106         
00107         categorizeUpdates(result, info);
00108         
00109         return result;
00110 }
00111 
00121 gboolean
00122 luau_installUpdate(const AProgInfo *info, const AUpdate *newUpdate, const APkgType type) {
00123         char *filename, *actualFilename;
00124         gboolean result;
00125         
00126         filename = lutil_getTempFilename();
00127         
00128         actualFilename = luau_downloadUpdate(info, newUpdate, type, filename);
00129         result = luau_installPackage(actualFilename, type);
00130         
00131         g_free(filename);
00132         g_free(actualFilename);
00133         
00134         return result;
00135 }
00136 
00151 char *
00152 luau_downloadUpdate(const AProgInfo *info, const AUpdate *newUpdate, const APkgType type, const char* downloadTo) {
00153         char *actualFilename = NULL, *temp;
00154         APackage *pkg;
00155         struct stat fileinfo;
00156         int ret;
00157         gboolean result = FALSE;
00158         
00159         if (downloadTo != NULL && downloadTo[0] != '\0') {
00160                 while (result == FALSE) {
00161                         ret = stat(downloadTo, &fileinfo);
00162                         if (ret == -1) {
00163                                 if (errno != ENOENT) {
00164                                         ERROR("Can't write to %s: %s", downloadTo, strerror(errno));
00165                                         return NULL;
00166                                 } else {
00167                                         actualFilename = g_strdup(downloadTo);
00168                                         result = TRUE;
00169                                 }
00170                         } else {
00171                                 if (S_ISREG(fileinfo.st_mode)) {
00172                                         ret = lutil_error_prompt("File Exists", "The specified download location already exists.  What would you like to do?", 2, 0, "Overwrite", "Cancel");
00173                                         if (ret == 0) {
00174                                                 DBUGOUT("File '%s' exists: overwriting", downloadTo);
00175                                                 result = TRUE;
00176                                         } else {
00177                                                 ERROR("File '%s' exists: not overwriting", downloadTo);
00178                                                 return NULL;
00179                                         }
00180                                 } else if (S_ISDIR(fileinfo.st_mode)) {
00181                                         DBUGOUT("Is a directory: writing into that directory");
00182                                         pkg = luau_getUpdatePackage(newUpdate, type);
00183                                         temp = luau_getPackageURL(pkg);
00184                                         DBUGOUT("Preparing to download: %s", temp);
00185                                         temp = g_path_get_basename(temp);
00186                                         actualFilename = lutil_vstrcreate(downloadTo, "/", temp, NULL);
00187                                         g_free(temp);
00188                                         downloadTo = actualFilename;
00189                                         /* Loop back and check if this file now exists */
00190                                 } else {
00191                                         DBUGOUT("FIFO, device, symlink, or socket given: treating as regular file");
00192                                         result = TRUE;
00193                                 }
00194                         }
00195                 }
00196                 
00197                 if (actualFilename == NULL)
00198                         actualFilename = g_strdup(downloadTo);
00199         } else {
00200                 ERROR("No filename given!");
00201                 return NULL;
00202         }
00203         
00204         result = luau_net_downloadUpdate(info, newUpdate, type, actualFilename);
00205         
00206         if (result == FALSE) {
00207                 g_free(actualFilename);
00208                 ERROR("Could not download specified update");
00209                 actualFilename = NULL;
00210         }
00211         
00212         return actualFilename;
00213 }
00214 
00222 gboolean
00223 luau_installPackage(const char *filename, const APkgType type) {
00224         gboolean result = FALSE;
00225         
00226         switch (type) {
00227                 case LUAU_RPM:
00228                         result = luau_install_rpm(filename);
00229                         break;
00230                 case LUAU_DEB:
00231                         result = luau_install_deb(filename);
00232                         break;
00233                 case LUAU_SRC:
00234                         result = luau_install_src(filename);
00235                         break;
00236                 case LUAU_EXEC:
00237                         result = luau_install_exec(filename);
00238                         break;
00239                 case LUAU_AUTOPKG:
00240                         result = luau_install_autopkg(filename);
00241                         break;
00242                 default:
00243                         ERROR("Invalid packager type qualifier: %d", type);
00244                         result = FALSE;
00245         }
00246         /*
00247         if (result == TRUE)
00248                 luau_hideUpdate(info, newUpdate);
00249         */
00250         return result;
00251 }
00252 
00261 void
00262 luau_registerErrorFunc(AErrorFunc errorFunc) {
00263         lutil_error_setErrorFunc(errorFunc); // in error.[ch]
00264 }
00265 
00276 void
00277 luau_registerPromptFunc(APromptFunc promptFunc) {
00278         lutil_error_setPromptFunc(promptFunc);
00279 }
00280 
00291 void
00292 luau_registerProgressCallback(AProgressCallback callback) {
00293         lutil_ftp_setCallbackFunc(callback);
00294 }
00295 
00302 void
00303 luau_resetErrorFunc(void) {
00304         lutil_error_resetErrorFunc();
00305 }
00306 
00313 void
00314 luau_resetPromptFunc(void) {
00315         lutil_error_resetPromptFunc();
00316 }
00317 
00323 void
00324 luau_resetProgressCallback(void) {
00325         lutil_ftp_resetCallbackFunc();
00326 }
00327 
00328 
00329 
00330 
00331 /*
00332  *  *** UTILITY FUNCTIONS ***
00333  */
00334 
00343 APackage *
00344 luau_getUpdatePackage(const AUpdate *update, APkgType pkgType) {
00345         GPtrArray *updateArray = update->packages;
00346         APackage *temp, *result = NULL;
00347         int i;
00348         
00349         for (i = 0; i < updateArray->len; ++i) {
00350                 temp = g_ptr_array_index(updateArray, i);
00351                 if (temp->type == pkgType) {
00352                         result = temp;
00353                         break;
00354                 }
00355         }
00356         
00357         if (result == NULL) {
00358                 ERROR("No package of type %s in selected update!", luau_packageTypeString(pkgType));
00359                 return NULL;
00360         } else {
00361                 return result;
00362         }
00363 }
00364 
00372 char *
00373 luau_dateString(const ADate *date) {
00374         /* 04/28/2003 */
00375         char* string;
00376         if (date == NULL) {
00377                 string = g_strdup("(null)");
00378         } else {
00379                 string = lutil_mprintf("%.2d/%.2d/%.4d", date->month, date->day, date->year);
00380         }
00381         return string;
00382 }
00383 
00393 gboolean
00394 luau_parseDate(ADate *date, const char *string) {
00395         int ret;
00396         
00397         if (string == NULL) {
00398                 date->year = 0;
00399                 date->month = 0;
00400                 date->day = 0;
00401                 return FALSE;
00402         }
00403         
00404         memset(date, 0, sizeof(ADate));
00405         ret = sscanf(string, "%hd/%hd/%d", &(date->month), &(date->day), &(date->year));
00406         
00407         return (ret == 3);
00408 }
00409 
00420 int
00421 luau_datecmp(ADate *d1, ADate *d2) {
00422         int result;
00423         
00424         if (d1 == NULL || d2 == NULL)
00425                 return 0;
00426         else if ((result = lutil_intcmp(d1->year, d2->year)) != 0)
00427                 return result;
00428         else if ((result = lutil_intcmp(d1->month, d2->month)) != 0)
00429                 return result;
00430         else
00431                 return lutil_intcmp(d1->day, d2->day);
00432 }
00433 
00434 
00435 /*
00436  * compareVersions <REQUIRED> <CURRENT>
00437  * REQUIRED: Required version.
00438  * CURRENT: Current version.
00439  * Returns: 0 if passed, 1 if failed.
00440  *
00441  * This function compares 2 strings - infinite level of decimal groups.
00442  * REQUIRED string for required version; CURRENT string for current version.
00443  * Returns 1 if REQUIRED is > CURRENT, else 0. [ 0 - PASS, 1 - FAIL ]
00444  *
00445  * Parameter string format: "x.y.z", where y and z are optional. Wildcards can
00446  * only be used for an entire decimal group like "1.6.x" or "2.x" NOT "2.5x" .
00447  * Function looks ahead in the decimal groups with alphabetic and numeric
00448  * identifers to match full numbers. For instance REQUIRED:2-RC10f and
00449  * CURRENT:2-rc2d, it ends up comparing 10 to 2 and returns 1 [ FAIL ]
00450  * instead of 1 to 2 returning 0 [ PASS ].
00451  *
00452  * Example:
00453  *                     Required    Current          Return Value
00454  *    compareVersions  "1"         "1.2"       --->  0 [ PASS ]
00455  *    compareVersions  "1.2"       "1"         --->  1 [ FAIL ]
00456  *    compareVersions  "1.1"       "1.2"       --->  0 [ PASS ]
00457  *    compareVersions  "1.3"       "1.2"       --->  1 [ FAIL ]
00458  *    compareVersions  "1.2"       "1.2"       --->  0 [ PASS ]
00459  *    compareVersions  "1.2b"      "1.2b"      --->  0 [ PASS ]
00460  *    compareVersions  "2.5-pre3"  "2.5"       --->  0 [ PASS ]
00461  *    compareVersions  "2.5-pre3"  "2.5-pre2"  --->  1 [ FAIL ]
00462  *    compareVersions  "2-RC10f"   "2-rc2d"    --->  1 [ FAIL ]
00463  *    compareVersions  "3.1-RC3"   "3.1-rc12"  --->  0 [ PASS ]
00464  *    compareVersions  "1.3"       "0.1.5"     --->  1 [ FAIL ]
00465  *    compareVersions  "1.99.6"    "2"         --->  0 [ PASS ]
00466  *    compareVersions  "1.6.x"     "1.6.7"     --->  0 [ PASS ]
00467  *    compareVersions  "1.6.x"     "1.6"       --->  0 [ PASS ]
00468  *    compareVersions  "1.6.x"     "1.5.7"     --->  1 [ FAIL ]
00469  *    compareVersions  "1.x"       "1.5.7"     --->  0 [ PASS ]
00470  */
00471 
00472 int
00473 luau_versioncmp(const char *required, const char *current) {
00474         GContainer *reqElements, *curElements;
00475         char *req, *cur;
00476         int max, i, len, result, x, y;
00477         
00478         result = 0;
00479         
00480         req = g_strdup(required);
00481         cur = g_strdup(current);
00482         
00483         lutil_strToLower(req);
00484         lutil_strToLower(cur);
00485         
00486         /* replace all '-' '_' '/' '+' with '.' to index for arrays */
00487         len = strlen(req);
00488         for (i = 0; i < len; ++i) {
00489                 if (req[i] == '-' || req[i] == '_' || req[i] == '/' || req[i] == '+' || req[i] == '\\')
00490                                 req[i] = '.';
00491         }
00492         
00493         len = strlen(cur);
00494         for (i = 0; i < len; ++i) {
00495                 if (cur[i] == '-' || cur[i] == '_' || cur[i] == '/' || cur[i] == '+' || cur[i] == '\\')
00496                                 cur[i] = '.';
00497         }
00498         
00499         /* create arrays from parameters */
00500         reqElements = lutil_gsplit(".", req);
00501         curElements = lutil_gsplit(".", cur);
00502         
00503         g_free(req);
00504         g_free(cur);
00505         
00506         /* obtain maximum count of elements from either array */
00507         if (reqElements->len > curElements->len)
00508                 max = reqElements->len;
00509         else
00510                 max = curElements->len;
00511 
00512         for (i = 0; i < max; ++i) {
00513                 /* process each respective decimal group ...
00514                  * if alphanumeric group then extend the compare to compareAlphaNumeric, otherwise do integer comparisons */
00515                 
00516                 req = (i < reqElements->len) ? g_container_index(reqElements, i) : NULL;
00517                 cur = (i < curElements->len) ? g_container_index(curElements, i) : NULL;
00518                 
00519                 /* special case: if wildcard in either decimal group then they are "equal" */
00520                 if ((req != NULL && lutil_streq(req, "x")) || (cur != NULL && lutil_streq(cur, "x"))) {
00521                         result = 0;
00522                         break;
00523                 }
00524                 
00525                 if (lutil_containsAlpha(cur) || lutil_containsAlpha(req)) {
00526                         result = compareAlphaNumeric(req, cur);
00527                         
00528                         if (result != 0)
00529                                 break;
00530                 } else if (req == NULL) {
00531                         result = -1;
00532                         break;
00533                 } else if (cur == NULL) {
00534                         result = 1;
00535                         break;
00536                 } else {
00537                         x = atoi(req);
00538                         y = atoi(cur);
00539                         
00540                         if (x != y) {
00541                                 result = (x < y) ? -1 : 1;
00542                                 break;
00543                         }
00544                 }
00545         }
00546         
00547         g_container_destroy(reqElements);
00548         g_container_destroy(curElements);
00549         
00550         return result;
00551 }
00552 
00560 gboolean
00561 luau_isOfType(APkgType query, APkgType type) {
00562   return ( (query & type) == 0 ? FALSE : TRUE);
00563 }
00564 
00574 char *
00575 luau_multPackageTypeString(APkgType types) {
00576         char *str = lutil_createString(25);
00577         int n;
00578         
00579         str[0] = '\0';
00580         if (luau_isOfType(types, LUAU_RPM))
00581                 strcat(str, "RPM ");
00582         if (luau_isOfType(types, LUAU_DEB))
00583                 strcat(str, "DEB ");
00584         if (luau_isOfType(types, LUAU_SRC))
00585                 strcat(str, "SRC ");
00586         if (luau_isOfType(types, LUAU_EXEC))
00587                 strcat(str, "EXEC ");
00588         if (luau_isOfType(types, LUAU_AUTOPKG))
00589                 strcat(str, "AUTOPKG ");
00590         
00591         if ((n = strlen(str)) != 0) {
00592                 str[n-1] = '\0'; /* Cut off trailing white space */
00593         } else if (types == LUAU_EMPTY) {
00594                 strcpy(str, "(none)");
00595         } else {
00596                 ERROR("Unrecognized package type: %d", types);
00597                 strcpy(str, "UNKNOWN");
00598         }
00599         
00600         return str;
00601 }
00602 
00612 const char *
00613 luau_packageTypeString(APkgType type) {
00614         const char *str = NULL;
00615         
00616         if (type == LUAU_RPM)
00617                 str = "RPM";
00618         else if (type == LUAU_DEB)
00619                 str = "DEB";
00620         else if (type == LUAU_SRC)
00621                 str = "SRC";
00622         else if (type == LUAU_EXEC)
00623                 str = "EXEC";
00624         else if (type == LUAU_AUTOPKG)
00625                 str = "AUTOPKG";
00626         else if (type == LUAU_EMPTY)
00627                 str = "(none)";
00628         else
00629                 str = "UNKNOWN";
00630         
00631         return str;
00632 }
00633 
00643 APkgType
00644 luau_parsePkgType(const char* typeString) {
00645         APkgType type = LUAU_UNKNOWN;
00646         if (lutil_streq(typeString, "RPM")) type = LUAU_RPM;
00647         else if (lutil_streq(typeString, "DEB")) type = LUAU_DEB;
00648         else if (lutil_streq(typeString, "SRC")) type = LUAU_SRC;
00649         else if (lutil_streq(typeString, "EXEC")) type = LUAU_EXEC;
00650         else if (lutil_streq(typeString, "autopackage")) type = LUAU_AUTOPKG;
00651         else if (lutil_streq(typeString, "AUTOPKG")) type = LUAU_AUTOPKG;
00652         return type;
00653 }
00654 
00655 char *
00656 luau_getPackageURL(APackage *pkgInfo) {
00657         GPtrArray *mirrors = pkgInfo->mirrors;
00658         char *loc = NULL;
00659         int percentage, random, i;
00660 
00661 #ifdef DEBUG
00662         for (i = 0; i < mirrors->len; i += 2)
00663                 DBUGOUT("URL: %s; weight: %d\n", (char*)g_ptr_array_index(mirrors, i+1), GPOINTER_TO_INT (g_ptr_array_index(mirrors, i)));
00664 #endif /* DEBUG */
00665         
00666         if (mirrors == NULL || mirrors->len == 0)
00667                 return NULL;
00668         else if (mirrors->len == 2)
00669                 return g_ptr_array_index(mirrors, 1);
00670         
00671         random = rand() % 100; /* integer between 0 and 100 */
00672         
00673         for (i = 0; i < mirrors->len; i+=2) {
00674                 percentage = GPOINTER_TO_INT( g_ptr_array_index(mirrors, i) );
00675                 if (random <= percentage) {
00676                         loc = g_ptr_array_index(mirrors, i+1);
00677                         break;
00678                 } else {
00679                         random -= percentage;
00680                 }
00681         }
00682         
00683         if (loc == NULL && mirrors->len >= 2)
00684                 loc = g_ptr_array_index(mirrors, 1);
00685         
00686         return loc;
00687 }
00688 
00696 GSList *
00697 luau_packageTypeList(APkgType types) {
00698         GSList *list = NULL;
00699         
00700         if (luau_isOfType(types, LUAU_RPM))
00701                 list = g_slist_append(list, GINT_TO_POINTER (LUAU_RPM));
00702         if (luau_isOfType(types, LUAU_DEB))
00703                 list = g_slist_append(list, GINT_TO_POINTER (LUAU_DEB));
00704         if (luau_isOfType(types, LUAU_SRC))
00705                 list = g_slist_append(list, GINT_TO_POINTER (LUAU_SRC));
00706         if (luau_isOfType(types, LUAU_EXEC))
00707                 list = g_slist_append(list, GINT_TO_POINTER (LUAU_EXEC));
00708         if (luau_isOfType(types, LUAU_AUTOPKG))
00709                 list = g_slist_append(list, GINT_TO_POINTER (LUAU_AUTOPKG));
00710         
00711         return list;
00712 }
00713 
00721 const char *
00722 luau_updateTypeString(AUpdateType type) {
00723         switch (type) {
00724                 case LUAU_SOFTWARE: return "Software";
00725                 case LUAU_MESSAGE: return "Message";
00726                 case LUAU_LIBUPDATE: return "Luau Config";
00727                 default: return "UNKNOWN";
00728         }
00729 }
00730 
00737 char *
00738 luau_progInfoString(const AProgInfo *info) {
00739         char *str, *keywordsStr, *dateStr;
00740         
00741         keywordsStr = luau_keywordsString(info->keywords);
00742         dateStr = luau_dateString(info->date);
00743         str = lutil_mprintf("{ ID => %s,\n  Name => %s,\n  Desc => %s,\n  URL => %s,\n  Version => %s,\n Date => %s,\n Keywords => %s\n}",
00744                              info->id, info->fullname, info->desc, info->url, info->version, dateStr, keywordsStr);
00745         
00746         g_free(keywordsStr);
00747         g_free(dateStr);
00748         
00749         return str;
00750 }
00751 
00759 char *
00760 luau_keywordsString(const GPtrArray *keywords) {
00761         GContainer *keyCont;
00762         char *str;
00763         
00764         if (keywords == NULL)
00765                 str = g_strdup("");
00766         else {
00767                 keyCont = g_container_new_from_data(GCONT_PTR_ARRAY, (void*)keywords);
00768                 str = lutil_strjoin(", ", keyCont);
00769                 g_container_free(keyCont, FALSE);
00770         }
00771         
00772         return str;
00773 }
00774 
00781 void
00782 luau_setKeyword(GPtrArray *keywords, const char *newKeyword) {
00783         if (keywords != NULL && newKeyword != NULL)
00784                 g_ptr_array_add(keywords, g_strdup(newKeyword));
00785 }
00786 
00795 gboolean
00796 luau_unsetKeyword(GPtrArray *keywords, const char *oldKeyword) {
00797         int i;
00798         gboolean found = FALSE;
00799         char *curr;
00800         
00801         for (i = 0; i < keywords->len; ++i) {
00802                 curr = g_ptr_array_index(keywords, i);
00803                 if (lutil_streq(curr, oldKeyword)) {
00804                         found = TRUE;
00805                         g_ptr_array_remove_index_fast(keywords, i);
00806                         break;
00807                 }
00808         }
00809         
00810         return found;
00811 }
00812 
00820 gboolean
00821 luau_checkKeyword(const GPtrArray *keywords, const char *needle) {
00822         GContainer *cont;
00823         gboolean result;
00824         
00825         if (keywords != NULL && needle != NULL) {
00826                 cont = g_container_new_from_data(GCONT_PTR_ARRAY, (void*)keywords);
00827                 result = lutil_findString(cont, needle);
00828                 g_container_free(cont, FALSE);
00829         }
00830         else
00831                 result = FALSE;
00832         
00833         return result;
00834 }
00835 
00842 gboolean
00843 luau_isIncompatible(AUpdate *update) {
00844         if (update != NULL && update->keywords != NULL)
00845                 return luau_checkKeyword(update->keywords, "_incompatible");
00846         else
00847                 return FALSE;
00848 }
00849 
00856 gboolean
00857 luau_isHidden(AUpdate *update) {
00858         if (update != NULL && update->keywords != NULL)
00859                 return luau_checkKeyword(update->keywords, "_hidden");
00860         else
00861                 return FALSE;
00862 }
00863 
00864 gboolean
00865 luau_isOld(AUpdate *update) {
00866         if (update != NULL && update->keywords != NULL)
00867                 return luau_checkKeyword(update->keywords, "_old");
00868         else
00869                 return FALSE;
00870 }
00871 
00872 gboolean
00873 luau_isVisible(AUpdate *update) {
00874         return !(luau_isOld(update) || luau_isHidden(update) || luau_isIncompatible(update));
00875 }
00876 
00889 gboolean
00890 luau_satisfiesInterface(const AInterface *wanted, const AInterface *needed) {
00891         return ((wanted->major == needed->major) && (wanted->minor >= needed->minor));
00892 }
00893 
00894 gboolean
00895 luau_satisfiesQuant(const AQuantifier *needed, const AProgInfo *installed) {
00896         gboolean result;
00897         int compare;
00898         
00899         /* Note that if one of the quantifiers is invalid (anywhere you see an "ERROR" call here), we
00900            return TRUE - in essense, we ignore that the quantifier even exists by saying that any
00901            program version satisfies it */
00902         
00903         if (needed->dtype == LUAU_QUANT_DATA_INTERFACE) {
00904                 if (needed->qtype == LUAU_QUANT_FOR)
00905                         result = luau_satisfiesInterface(&(installed->interface), (AInterface*) needed->data);
00906                 else {
00907                         ERROR("Interface quantifiers can only be of type 'for', not of 'from' or 'to'");
00908                         result = TRUE;
00909                 }
00910         } else if (needed->dtype == LUAU_QUANT_DATA_KEYWORD) {
00911                 if (needed->qtype == LUAU_QUANT_FOR)
00912                         result = luau_checkKeyword(installed->keywords, (char*)needed->data);
00913                 else {
00914                         ERROR("Keyword quantifiers can only be of type 'for', not of 'from' or 'to'");
00915                         result = TRUE;
00916                 }
00917         } else if (needed->dtype == LUAU_QUANT_DATA_DATE || needed->dtype == LUAU_QUANT_DATA_VERSION) {
00918                 if (needed->dtype == LUAU_QUANT_DATA_DATE)
00919                         compare = luau_datecmp(installed->date, (ADate*) needed->data);
00920                 else /* needed->dtype == LUAU_QUANT_DATA_VERSION */
00921                         compare = luau_versioncmp(installed->version, (const char *) needed->data);
00922                 
00923                 if (needed->qtype == LUAU_QUANT_FOR)
00924                         result = (compare == 0);
00925                 else if (needed->qtype == LUAU_QUANT_FROM)
00926                         result = (compare != -1); /* Inclusive */
00927                 else if (needed->qtype == LUAU_QUANT_TO)
00928                         result = (compare == -1); /* Exclusive */
00929                 else {
00930                         ERROR("Internal Error: Unrecognized quantifier type (%d)", needed->qtype);
00931                         result = TRUE;
00932                 }
00933         } else {
00934                 ERROR("Internal Error: Unrecognized quantifier data type (%d)", needed->dtype);
00935                 result = TRUE;
00936         }
00937         
00938         return result;
00939 }
00940 
00941 AQuantDataType
00942 luau_parseQuantDataType(const char *str) {
00943         AQuantDataType type;
00944         
00945         if (lutil_strcaseeq(str, "version"))
00946                 type = LUAU_QUANT_DATA_VERSION;
00947         else if (lutil_strcaseeq(str, "interface"))
00948                 type = LUAU_QUANT_DATA_INTERFACE;
00949         else if (lutil_strcaseeq(str, "date"))
00950                 type = LUAU_QUANT_DATA_DATE;
00951         else if (lutil_strcaseeq(str, "keyword"))
00952                 type = LUAU_QUANT_DATA_KEYWORD;
00953         else
00954                 type = LUAU_QUANT_DATA_INVALID;
00955         
00956         return type;
00957 }
00958 
00969 gboolean
00970 luau_parseInterface(AInterface *interface, const char *intStr) {
00971         gboolean result = FALSE;
00972         int ret = 0;
00973         
00974         interface->major = -1;
00975         interface->minor = -1;
00976 
00977         if (intStr != NULL) {
00978                 if (lutil_isCompletelyBlank(intStr))
00979                         result = TRUE;
00980                 else {
00981                         ret = sscanf(intStr, "%d.%d", &(interface->major), &(interface->minor));
00982                         result = (ret == 2);
00983                 }
00984         }
00985         
00986         return result;
00987 }
00988 
00997 char *
00998 luau_interfaceString(const AInterface *interface) {
00999         char *ret;
01000         
01001         if (interface->major == -1 && interface->minor == -1)
01002                 ret = g_strdup("");
01003         else
01004                 ret = lutil_mprintf("%d.%d", interface->major, interface->minor);
01005         
01006         return ret;
01007 }
01008 
01009 
01010 /* Structure copying */
01011 
01018 void
01019 luau_copyUpdate(AUpdate *dest, const AUpdate *src) {
01020         APackage *destPkg, *srcPkg;
01021         int i;
01022         
01023         if (dest == NULL || src == NULL) {
01024                 DBUGOUT("Null pointer passed to luau_copyUpdate");
01025         } else {
01026                 /* Note that g_strdup(NULL) == NULL, as desired for this code block */
01027                 dest->id = g_strdup(src->id);
01028                 dest->shortDesc = g_strdup(src->shortDesc);
01029                 dest->fullDesc = g_strdup(src->fullDesc);
01030                 dest->newVersion = g_strdup(src->newVersion);
01031                 dest->newURL = g_strdup(src->newURL);
01032                 
01033                 dest->type = src->type;
01034                 dest->availableFormats = src->availableFormats;
01035                 luau_copyInterface(&(dest->interface), &(src->interface));
01036                 
01037                 if (src->keywords != NULL) {
01038                         GContainer *destCont, *srcCont;
01039 
01040                         dest->keywords = g_ptr_array_new();
01041                         destCont = g_container_new_from_data(GCONT_PTR_ARRAY, dest->keywords);
01042                         srcCont = g_container_new_from_data(GCONT_PTR_ARRAY, src->keywords);
01043                         g_container_copy(destCont, srcCont);
01044                         g_container_free(srcCont, FALSE);
01045                         g_container_free(destCont, FALSE);
01046                 } else {
01047                         dest->keywords = NULL;
01048                 }
01049                 if (src->packages != NULL) {
01050                         dest->packages = g_ptr_array_new();
01051                         for (i = 0; i < src->packages->len; ++i) {
01052                                 srcPkg = g_ptr_array_index(src->packages, i);
01053                                 destPkg = g_malloc(sizeof(APackage));
01054                                 
01055                                 luau_copyPackage(destPkg, srcPkg);
01056                                 g_ptr_array_add(dest->packages, destPkg);
01057                         }
01058                 } else {
01059                         dest->packages = NULL;
01060                 }
01061                 
01062                 if (src->date != NULL) {
01063                         dest->date = g_malloc(sizeof(ADate));
01064                         luau_copyDate(dest->date, src->date);
01065                 } else {
01066                         dest->date = NULL;
01067                 }
01068                 
01069                 if (src->quantifiers != NULL) {
01070                         dest->quantifiers = g_ptr_array_new();
01071                         luau_copyQuants(dest->quantifiers, src->quantifiers);
01072                 } else {
01073                         dest->quantifiers = NULL;
01074                 }
01075                 
01076                 /*if (src->newDate != NULL) {
01077                         dest->newDate = g_malloc(sizeof(ADate));
01078                         luau_copyDate(dest->newDate, src->newDate);
01079                 } else {
01080                         dest->newDate = NULL;
01081                 }*/
01082         }
01083 }
01084 
01085 void
01086 luau_copyPackage(APackage *dest, const APackage *src) {
01087         int i, curr;
01088         if (dest == NULL || src == NULL) {
01089                 DBUGOUT("Null pointer passed to luau_copyPackage");
01090         } else {
01091                 dest->type = src->type;
01092                 dest->size = src->size;
01093                 strncpy(dest->md5sum, src->md5sum, 33);
01094                 if (src->mirrors != NULL) {
01095                         dest->mirrors = g_ptr_array_new();
01096                         for (i = 0; i < src->mirrors->len; i++) {
01097                                 if (i%2) /* odd entries => strings */
01098                                         g_ptr_array_add(dest->mirrors, g_strdup(g_ptr_array_index(src->mirrors, i)));
01099                                 else { /* even entries => integers */
01100                                         curr = GPOINTER_TO_INT (g_ptr_array_index(src->mirrors, i));
01101                                         g_ptr_array_add(dest->mirrors, GINT_TO_POINTER (curr));
01102                                 }
01103                         }
01104                 }
01105         }
01106         
01107 #ifdef DEBUG
01108         for (i = 0; i < dest->mirrors->len; i += 2)
01109                 DBUGOUT("URL: %s; weight: %d\n", (char*)g_ptr_array_index(dest->mirrors, i+1), GPOINTER_TO_INT (g_ptr_array_index(dest->mirrors, i)));
01110 #endif /* DEBUG */
01111 
01112 }
01113 
01120 void
01121 luau_copyProgInfo(AProgInfo *dest, const AProgInfo *src) {
01122         if (dest == NULL || src == NULL) { 
01123                 DBUGOUT("Null pointer passed to luau_copyProgInfo");
01124         } else {
01125                 dest->id = g_strdup(src->id);
01126                 dest->shortname = g_strdup(src->shortname);
01127                 dest->fullname = g_strdup(src->fullname);
01128                 dest->desc = g_strdup(src->desc);
01129                 dest->url = g_strdup(src->url);
01130                 dest->version = g_strdup(src->version);
01131                 
01132                 luau_copyInterface(&(dest->interface), &(src->interface));
01133                 
01134                 if (src->date != NULL) {
01135                         dest->date = g_malloc(sizeof(ADate));
01136                         luau_copyDate(dest->date, src->date);
01137                 } else {
01138                         dest->date = NULL;
01139                 }
01140                 if (src->keywords != NULL) {
01141                         GContainer *srcCont, *destCont;
01142                         dest->keywords = g_ptr_array_new();
01143                         srcCont = g_container_new_from_data(GCONT_PTR_ARRAY, src->keywords);
01144                         destCont = g_container_new_from_data(GCONT_PTR_ARRAY, dest->keywords);
01145                         g_container_copy(destCont, srcCont);
01146                         g_container_free(srcCont, FALSE);
01147                         g_container_free(destCont, FALSE);
01148                 } else {
01149                         dest->keywords = NULL;
01150                 }
01151         }
01152 }
01153 
01160 void
01161 luau_copyInterface(AInterface *dest, const AInterface *src) {
01162         if (dest == NULL || src == NULL) {
01163                 DBUGOUT("Null pointer passed to luau_copyInterface");
01164         } else {
01165                 dest->major = src->major;
01166                 dest->minor = src->minor;
01167         }
01168 }
01169 
01176 void
01177 luau_copyDate(ADate *dest, const ADate *src) {
01178         if (dest == NULL || src == NULL) {
01179                 DBUGOUT("Null pointer passed to luau_copyDate");
01180         } else {
01181                 dest->year  = src->year;
01182                 dest->month = src->month;
01183                 dest->day   = src->day;
01184         }
01185 }
01186 
01187 void
01188 luau_copyQuants(GPtrArray *dest, const GPtrArray *src) {
01189         AQuantifier *quant;
01190         int i;
01191         
01192         for (i = 0; i < src->len; ++i) {
01193                 quant = g_malloc(sizeof(AQuantifier));
01194                 luau_copyQuant(quant, g_ptr_array_index(src, i));
01195                 g_ptr_array_add(dest, quant);
01196         }
01197 }
01198 
01199 void
01200 luau_copyQuant(AQuantifier *dest, const AQuantifier *src) {
01201         dest->qtype = src->qtype;
01202         dest->dtype = src->dtype;
01203         
01204         switch (dest->dtype) {
01205                 case LUAU_QUANT_DATA_DATE:
01206                         dest->data = g_malloc(sizeof(ADate));
01207                         luau_copyDate(dest->data, src->data);
01208                         break;
01209 
01210                 case LUAU_QUANT_DATA_VERSION:
01211                 case LUAU_QUANT_DATA_INTERFACE:
01212                 case LUAU_QUANT_DATA_KEYWORD:
01213                         dest->data = g_strdup(src->data);
01214                         break;
01215                 
01216                 default:
01217                         ERROR("Invalid Quantifier Data type - can't copy");
01218         }
01219 }
01220 
01221 
01222 /* Memory management */
01223 
01229 void
01230 luau_freeUpdateArray(GPtrArray *updates) {
01231         AUpdate *curr;
01232         int i;
01233         
01234         if (updates != NULL) {
01235                 for (i = 0; i < updates->len; ++i) {
01236                         curr = g_ptr_array_index(updates, i);
01237                         luau_freeUpdateInfo(curr);
01238                         g_free(curr);
01239                 }
01240                 
01241                 g_ptr_array_free(updates, TRUE);
01242         }
01243 }
01244 
01250 void
01251 luau_freeProgInfo(AProgInfo *ptr) {
01252         if (ptr != NULL) {
01253                 int i;
01254                 nnull_g_free(ptr->id);
01255                 nnull_g_free(ptr->shortname);
01256                 nnull_g_free(ptr->fullname);
01257                 nnull_g_free(ptr->desc);
01258                 nnull_g_free(ptr->url);
01259                 nnull_g_free(ptr->version);
01260                 nnull_g_free(ptr->displayVersion);
01261                 nnull_g_free(ptr->date);
01262                 if (ptr->keywords != NULL) {
01263                         for (i = 0; i < ptr->keywords->len; ++i)
01264                                 g_free(g_ptr_array_index(ptr->keywords, i));
01265                         g_ptr_array_free(ptr->keywords, TRUE);
01266                 }
01267         } else {
01268                 ERROR("Attempt to free NULL pointer");
01269         }
01270 }
01271 
01277 void
01278 luau_freeUpdateInfo(AUpdate *ptr) {
01279         APackage *pkg;
01280         AQuantifier *quant;
01281         int i;
01282         
01283         if (ptr != NULL) {
01284                 nnull_g_free(ptr->id);
01285                 nnull_g_free(ptr->date);
01286                 nnull_g_free(ptr->shortDesc);
01287                 nnull_g_free(ptr->fullDesc);
01288                 nnull_g_free(ptr->newVersion);
01289                 nnull_g_free(ptr->newURL);
01290                 
01291                 if (ptr->keywords != NULL) {
01292                         for (i = 0; i < ptr->keywords->len; ++i)
01293                                 g_free(g_ptr_array_index(ptr->keywords, i));
01294                         g_ptr_array_free(ptr->keywords, TRUE);
01295                 }
01296                 if (ptr->packages != NULL) {
01297                         for (i = 0; i < ptr->packages->len; ++i) {
01298                                 pkg = g_ptr_array_index(ptr->packages, i);
01299                                 luau_freePkgInfo(pkg);
01300                                 g_free(pkg);
01301                         }
01302                         g_ptr_array_free(ptr->packages, TRUE);
01303                 }
01304                 if (ptr->quantifiers != NULL) {
01305                         for (i = 0; i < ptr->quantifiers->len; ++i) {
01306                                 quant = g_ptr_array_index(ptr->quantifiers, i);
01307                                 g_free(quant->data);
01308                                 g_free(quant);
01309                         }
01310                         g_ptr_array_free(ptr->quantifiers, TRUE);
01311                 }
01312         } else {
01313                 ERROR("Attempt to free NULL pointer");
01314         }
01315 }
01316 
01322 void
01323 luau_freePkgInfo(APackage *ptr) {
01324         int i;
01325         
01326         if (ptr != NULL) {
01327                 if (ptr->mirrors != NULL) {
01328                         for (i = 1; i < ptr->mirrors->len; i+=2)
01329                                 g_free(g_ptr_array_index(ptr->mirrors, i));
01330                         g_ptr_array_free(ptr->mirrors, TRUE);
01331                 }
01332         } else {
01333                 ERROR("Attempt to free NULL pointer");
01334         }
01335 }
01336 
01337 
01338 /* Non-Interface Methods */
01339 
01340 /* compareAlphaNumeric <VERSION1> <VERSION2>
01341  * Returns: 1 or 0.
01342  *
01343  * Compare two strings and return 1 if VERSION1 > VERSION2, otherwise 0.
01344  * Otherwise, gathers digits forward to compare full numbers.
01345  */
01346 
01347 static int
01348 compareAlphaNumeric(const char *v1, const char *v2) {
01349         int i, len1, len2, limit, result = 0;
01350         
01351         if (v1 == NULL)
01352                 v1 = "";
01353         if (v2 == NULL)
01354                 v2 = "";
01355         
01356         /* get length of the longest string to index with over as $limit */
01357         len1 = strlen(v1);
01358         len2 = strlen(v2);
01359         if (len1 > len2)
01360                 limit = len1;
01361         else
01362                 limit = len2;
01363         
01364         for (i = 0; i < limit; ++i) {
01365                 char char1, char2;
01366                 int val1, val2;
01367                 
01368                 /* compare character by character indexing up the string */
01369                 if (i < len1)
01370                         char1 = v1[i];
01371                 else
01372                         char1 = '\0';
01373                 
01374                 if (i < len2)
01375                         char2 = v2[i];
01376                 else
01377                         char2 = '\0';
01378                 
01379                 /* special case: point release is higher than alphabetic release
01380                  * example: REQUIRED 2.5-pre3 < CURRENT 2.5 or REQUIRED alpha-char < CURRENT no char */
01381                 if (! isdigit(char1) && char2 == '\0')
01382                         return -1;
01383 
01384                 /* look forward to find next index digit to complete the full number */
01385                 if (isdigit(v1[i]))
01386                         val1 = atoi(v1 + i);
01387                 else if (char1 == '\0')
01388                         val1 = 0;
01389                 else
01390                         val1 = -1;
01391                 
01392                 if (isdigit(v2[i]))
01393                         val2 = atoi(v2 + i);
01394                 else if (char2 == '\0')
01395                         val2 = 0;
01396                 else
01397                         val2 = -1;
01398 
01399                 /* if comparing numbers do an integer compare - otherwise do a string compare */
01400                 if (val1 != -1 || val2 != -1) {
01401                         if (val1 > val2) {
01402                                 result = 1;
01403                                 break;
01404                         } else if (val1 < val2) {
01405                                 result = -1;
01406                                 break;
01407                         } else if (val1 >= 10) {
01408                                 /* Skip over digits of number we just checked */
01409                                 i += log10(val1);
01410                         }
01411                 } else if (char1 < char2) {
01412                         result = -1;
01413                         break;
01414                 } else if (char1 > char2) {
01415                         result = 1;
01416                         break;
01417                 }
01418         }
01419         
01420         return result;
01421 }
01422 
01423 
01431 static void
01432 categorizeUpdates(GPtrArray *updates, const AProgInfo *progInfo) {
01433         AUpdate *curr;
01434         int i;
01435         
01436         if (updates == NULL)
01437                 return;
01438         
01439         for (i = 0; i < updates->len; ++i) {
01440                 curr = g_ptr_array_index(updates, i);
01441                 if (isIncompatible(curr, progInfo))
01442                         luau_setKeyword(curr->keywords, "_incompatible");
01443                 if (isOld(curr, progInfo))
01444                         luau_setKeyword(curr->keywords, "_old");
01445         }
01446 }
01447 
01455 static gboolean
01456 isIncompatible(AUpdate *update, const AProgInfo *progInfo) {
01457         AQuantifier *curr;
01458         gboolean compatible = TRUE;
01459         int i;
01460         
01461         if (update->quantifiers == NULL)
01462                 compatible = TRUE;
01463         else {
01464                 for (i = 0; i < update->quantifiers->len; ++i) {
01465                         curr = g_ptr_array_index(update->quantifiers, i);
01466                         
01467                         if (! luau_satisfiesQuant(curr, progInfo)) {
01468                                 compatible = FALSE;
01469                                 break;
01470                         }
01471                 }
01472         }
01473         
01474         return (!compatible);
01475 }
01476 
01477 static gboolean
01478 isOld(AUpdate *update, const AProgInfo *progInfo) {
01479         gboolean result;
01480         int ret;
01481         
01482         if (update->newVersion == NULL || progInfo->version == NULL)
01483                 result = FALSE;
01484         else {
01485                 ret = luau_versioncmp(update->newVersion, progInfo->version);
01486                 result = (ret != 1);
01487         }
01488         
01489         return result;
01490 }
01491 
01492 
01493 
01494 

Generated on Mon Apr 12 22:17:11 2004 for luau by doxygen 1.3.2