diff -Naur memcached-1.2.2/items.c memcached-1.2.2_mod/items.c
--- memcached-1.2.2/items.c	2007-05-02 17:58:51.000000000 -0500
+++ memcached-1.2.2_mod/items.c	2007-05-18 10:20:15.000000000 -0500
@@ -300,6 +300,33 @@
     return buffer;
 }
 
+/* Fil added: a very rough name search function */
+void item_search(char *prefix, char *buffer, const int buflen) {
+    item *it;
+    int len;
+    int i;
+    char *bufcurr = buffer;
+
+    if( prefix[0] == 42 ) // if wildcard '*' show all variable names
+       len = 0;
+    else
+       len = strlen(prefix);
+
+    for (i=0; i<LARGEST_ID; i++) {
+        it = heads[i];
+   
+        while (it) {
+            if ( (len==0 || strncmp(prefix, ITEM_key(it), len)==0) &&
+                 (it->it_flags & ITEM_LINKED) && (it->it_flags & ITEM_DELETED)==0 && (current_time - it->exptime) > 0 ){
+                bufcurr += snprintf(bufcurr, (size_t)buflen, "%s\r\n", ITEM_key(it) );
+            }
+            it = it->next;
+        }
+    }
+    memcpy(bufcurr, "END", 4);
+    return;
+}
+
 void item_stats(char *buffer, const int buflen) {
     int i;
     char *bufcurr = buffer;
diff -Naur memcached-1.2.2/memcached.c memcached-1.2.2_mod/memcached.c
--- memcached-1.2.2/memcached.c	2007-05-02 17:58:51.000000000 -0500
+++ memcached-1.2.2_mod/memcached.c	2007-05-18 10:27:15.000000000 -0500
@@ -1054,6 +1054,9 @@
     item *it;
     token_t *key_token = &tokens[KEY_TOKEN];
 
+    char *exptime[16];
+    int exptime_len;
+
     assert(c != NULL);
 
     if (settings.managed) {
@@ -1103,8 +1106,13 @@
                  *   key
                  *   " " + flags + " " + data length + "\r\n" + data (with \r\n)
                  */
+
+                /* Fil added: we calculate the remaining time before expiry */
+                exptime_len = snprintf(exptime, 16, " %lu", it->exptime - current_time );
+
                 if (add_iov(c, "VALUE ", 6) != 0 ||
                     add_iov(c, ITEM_key(it), it->nkey) != 0 ||
+                    add_iov(c, exptime, exptime_len) !=0 || /* insert the time-till-expiry after key name */
                     add_iov(c, ITEM_suffix(it), it->nsuffix + it->nbytes) != 0)
                     {
                         break;
@@ -1162,8 +1170,8 @@
     size_t nkey;
     int flags;
     time_t exptime;
-    int vlen;
-    item *it;
+    int vlen, old_vlen;
+    item *it, *old_it;
 
     assert(c != NULL);
 
@@ -1201,6 +1209,18 @@
         }
     }
 
+    /* Fil added: Check if append -- if yes, search for previous entry, and allocate memory for both */
+    if( comm == NREAD_APPEND ){
+       old_it = assoc_find(key,nkey);
+
+       if( old_it && (old_it->nbytes)>2 ){ // previous must be more than \r\n
+          old_vlen = old_it->nbytes - 2;
+          vlen += old_vlen;                // append the length of old data
+       } else {
+          comm = NREAD_REPLACE;            // no old entry: treat as replace
+       }
+    }
+
     it = item_alloc(key, nkey, flags, realtime(exptime), vlen+2);
 
     if (it == 0) {
@@ -1214,9 +1234,20 @@
         return;
     }
 
-    c->item_comm = comm;
     c->item = it;
     c->ritem = ITEM_data(it);
+
+    /* Fil added: If append, prepend old data before new - adjust item, rlbytes variables too
+     * Now that data has been merged, treat simply as a replace command
+     */
+    if( comm == NREAD_APPEND ){
+       memcpy( c->ritem, ITEM_data(old_it), old_vlen );
+       c->ritem+=old_vlen;
+       c->rlbytes-=old_vlen;
+       comm = NREAD_REPLACE;
+    }
+
+    c->item_comm = comm;
     c->rlbytes = it->nbytes;
     conn_set_state(c, conn_nread);
 }
@@ -1451,7 +1482,8 @@
     } else if (ntokens == 6 &&
                ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) ||
                 (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) ||
-                (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)))) {
+                (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) ||
+                (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) {
 
         process_update_command(c, tokens, ntokens, comm);
 
@@ -1467,6 +1499,23 @@
 
         process_delete_command(c, tokens, ntokens);
 
+    /* Fil added: prefix search command, ex "search aa" returns all keys starting with aa */
+    } else if (ntokens == 3 && (strcmp(tokens[COMMAND_TOKEN].value, "search") == 0)) {
+        char *key;
+        size_t nkey;
+        char buffer[4096]; // bug: limited size to 4096 bytes of response
+
+        key = tokens[KEY_TOKEN].value;
+        nkey = tokens[KEY_TOKEN].length;
+
+        if(nkey > KEY_MAX_LENGTH) {
+           out_string(c, "CLIENT_ERROR bad command line format");
+           return;
+        }
+
+        item_search(key, buffer, 4096);
+        out_string(c, buffer);
+
     } else if (ntokens == 3 && strcmp(tokens[COMMAND_TOKEN].value, "own") == 0) {
         unsigned int bucket, gen;
         if (!settings.managed) {
diff -Naur memcached-1.2.2/memcached.h memcached-1.2.2_mod/memcached.h
--- memcached-1.2.2/memcached.h	2007-05-02 17:58:51.000000000 -0500
+++ memcached-1.2.2_mod/memcached.h	2007-05-18 10:19:15.000000000 -0500
@@ -128,6 +128,7 @@
 #define NREAD_ADD 1
 #define NREAD_SET 2
 #define NREAD_REPLACE 3
+#define NREAD_APPEND 4
 
 typedef struct {
     int    sfd;
