Skip to content
This repository
Browse code

windows sockets with IOCP

  • Loading branch information...
commit ac1cdea778a7f7e9e2322e13290389fc4baabf27 1 parent 734dabb
Henry Rawas authored Igor Zinkovsky committed

Showing 64 changed files with 4,497 additions and 240 deletions. Show diff stats Hide diff stats

  1. 20  .gitignore
  2. 11  deps/hiredis/async.c
  3. 65  deps/hiredis/dict.c
  4. 10  deps/hiredis/dict.h
  5. 90  deps/hiredis/hiredis.c
  6. 20  deps/hiredis/hiredis.h
  7. 180  deps/hiredis/net.c
  8. 9  deps/hiredis/sds.h
  9. 246  deps/linenoise/linenoise.c
  10. 101  msvs/RedisBenchmark/RedisBenchmark.vcxproj
  11. 82  msvs/RedisCheckAof/RedisCheckAof.vcxproj
  12. 85  msvs/RedisCheckDump/RedisCheckDump.vcxproj
  13. 95  msvs/RedisCli/RedisCli.vcxproj
  14. 56  msvs/RedisServer.sln
  15. 152  msvs/RedisServer.vcxproj
  16. 100  msvs/hiredis/hiredis.vcxproj
  17. 27  src/ae.c
  18. 224  src/ae_wsiocp.c
  19. 233  src/anet.c
  20. 120  src/aof.c
  21. 13  src/bio.c
  22. 58  src/config.c
  23. 4  src/db.c
  24. 10  src/debug.c
  25. 89  src/dict.c
  26. 13  src/dict.h
  27. 4  src/fmacros.h
  28. 4  src/intset.c
  29. 14  src/lzf_c.c
  30. 2  src/lzf_d.c
  31. 245  src/networking.c
  32. 4  src/object.c
  33. 10  src/pqsort.c
  34. 2  src/pubsub.c
  35. 44  src/rdb.c
  36. 82  src/redis-benchmark.c
  37. 50  src/redis-check-aof.c
  38. 94  src/redis-check-dump.c
  39. 46  src/redis-cli.c
  40. 159  src/redis.c
  41. 16  src/redis.h
  42. 7  src/release.c
  43. 181  src/replication.c
  44. 37  src/sds.c
  45. 4  src/sds.h
  46. 7  src/sha1.c
  47. 14  src/sort.c
  48. 9  src/syncio.c
  49. 10  src/t_hash.c
  50. 38  src/t_list.c
  51. 2  src/t_set.c
  52. 39  src/t_zset.c
  53. 28  src/util.c
  54. 372  src/win32_wsiocp.c
  55. 74  src/win32_wsiocp.h
  56. 565  src/win32fixes.c
  57. 288  src/win32fixes.h
  58. 18  src/ziplist.c
  59. 7  src/zipmap.c
  60. 23  src/zmalloc.c
  61. 3  src/zmalloc.h
  62. 2  tests/integration/aof.tcl
  63. 116  tests/support/server.tcl
  64. 4  tests/unit/protocol.tcl
20  .gitignore
@@ -17,3 +17,23 @@ release.h
17 17
 src/transfer.sh
18 18
 src/configs
19 19
 src/redis-server.dSYM
  20
+*.user
  21
+*.exe
  22
+*.sdf
  23
+*.suo
  24
+deps/pthreads-win32/
  25
+msvs/Debug/
  26
+msvs/Release/
  27
+msvs/RedisBenchmark/Debug/
  28
+msvs/RedisBenchmark/Release/
  29
+msvs/RedisCheckAof/Debug/
  30
+msvs/RedisCheckAof/Release/
  31
+msvs/RedisCheckDump/Debug/
  32
+msvs/RedisCheckDump/Release/
  33
+msvs/RedisCli/Debug/
  34
+msvs/RedisCli/Release/
  35
+msvs/hiredis/Debug/
  36
+msvs/hiredis/Release/
  37
+msvs/ipch
  38
+msvs/RedisServer.opensdf
  39
+
11  deps/hiredis/async.c
@@ -30,7 +30,9 @@
30 30
  */
31 31
 
32 32
 #include <string.h>
33  
-#include <strings.h>
  33
+#ifndef _WIN32
  34
+  #include <strings.h>
  35
+#endif
34 36
 #include <assert.h>
35 37
 #include <ctype.h>
36 38
 #include "async.h"
@@ -38,6 +40,11 @@
38 40
 #include "sds.h"
39 41
 #include "util.h"
40 42
 
  43
+#ifdef _WIN32
  44
+#define strcasecmp _stricmp
  45
+#define strncasecmp _strnicmp
  46
+#endif
  47
+
41 48
 /* Forward declaration of function in hiredis.c */
42 49
 void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
43 50
 
@@ -47,8 +54,8 @@ static unsigned int callbackHash(const void *key) {
47 54
 }
48 55
 
49 56
 static void *callbackValDup(void *privdata, const void *src) {
50  
-    ((void) privdata);
51 57
     redisCallback *dup = malloc(sizeof(*dup));
  58
+    ((void) privdata);
52 59
     memcpy(dup,src,sizeof(*dup));
53 60
     return dup;
54 61
 }
65  deps/hiredis/dict.c
@@ -42,7 +42,11 @@
42 42
 /* -------------------------- private prototypes ---------------------------- */
43 43
 
44 44
 static int _dictExpandIfNeeded(dict *ht);
  45
+#ifdef _WIN32
  46
+static size_t _dictNextPower(size_t size); 
  47
+#else
45 48
 static unsigned long _dictNextPower(unsigned long size);
  49
+#endif
46 50
 static int _dictKeyIndex(dict *ht, const void *key);
47 51
 static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
48 52
 
@@ -85,6 +89,53 @@ static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
85 89
 }
86 90
 
87 91
 /* Expand or create the hashtable */
  92
+#ifdef _WIN32
  93
+static int dictExpand(dict *ht, size_t size) {
  94
+    dict n; /* the new hashtable */
  95
+    size_t realsize = _dictNextPower(size), i;
  96
+
  97
+    /* the size is invalid if it is smaller than the number of
  98
+     * elements already inside the hashtable */
  99
+    if (ht->used > size)
  100
+        return DICT_ERR;
  101
+
  102
+    _dictInit(&n, ht->type, ht->privdata);
  103
+    n.size = realsize;
  104
+    n.sizemask = realsize-1;
  105
+    n.table = calloc(realsize,sizeof(dictEntry*));
  106
+
  107
+    /* Copy all the elements from the old to the new table:
  108
+     * note that if the old hash table is empty ht->size is zero,
  109
+     * so dictExpand just creates an hash table. */
  110
+    n.used = ht->used;
  111
+    for (i = 0; i < ht->size && ht->used > 0; i++) {
  112
+        dictEntry *he, *nextHe;
  113
+
  114
+        if (ht->table[i] == NULL) continue;
  115
+
  116
+        /* For each hash entry on this slot... */
  117
+        he = ht->table[i];
  118
+        while(he) {
  119
+            unsigned int h;
  120
+
  121
+            nextHe = he->next;
  122
+            /* Get the new element index */
  123
+            h = dictHashKey(ht, he->key) & n.sizemask;
  124
+            he->next = n.table[h];
  125
+            n.table[h] = he;
  126
+            ht->used--;
  127
+            /* Pass to the next element */
  128
+            he = nextHe;
  129
+        }
  130
+    }
  131
+    assert(ht->used == 0);
  132
+    free(ht->table);
  133
+
  134
+    /* Remap the new hashtable in the old */
  135
+    *ht = n;
  136
+    return DICT_OK;
  137
+}
  138
+#else
88 139
 static int dictExpand(dict *ht, unsigned long size) {
89 140
     dict n; /* the new hashtable */
90 141
     unsigned long realsize = _dictNextPower(size), i;
@@ -130,6 +181,7 @@ static int dictExpand(dict *ht, unsigned long size) {
130 181
     *ht = n;
131 182
     return DICT_OK;
132 183
 }
  184
+#endif
133 185
 
134 186
 /* Add an element to the target hash table */
135 187
 static int dictAdd(dict *ht, void *key, void *val) {
@@ -303,6 +355,18 @@ static int _dictExpandIfNeeded(dict *ht) {
303 355
 }
304 356
 
305 357
 /* Our hash table capability is a power of two */
  358
+#ifdef _WIN32
  359
+static size_t _dictNextPower(size_t size) {
  360
+    size_t i = DICT_HT_INITIAL_SIZE;
  361
+
  362
+    if (size >= LONG_MAX) return LONG_MAX;
  363
+    while(1) {
  364
+        if (i >= size)
  365
+            return i;
  366
+        i *= 2;
  367
+    }
  368
+}
  369
+#else
306 370
 static unsigned long _dictNextPower(unsigned long size) {
307 371
     unsigned long i = DICT_HT_INITIAL_SIZE;
308 372
 
@@ -313,6 +377,7 @@ static unsigned long _dictNextPower(unsigned long size) {
313 377
         i *= 2;
314 378
     }
315 379
 }
  380
+#endif
316 381
 
317 382
 /* Returns the index of a free slot that can be populated with
318 383
  * an hash entry for the given 'key'.
10  deps/hiredis/dict.h
@@ -60,9 +60,15 @@ typedef struct dictType {
60 60
 typedef struct dict {
61 61
     dictEntry **table;
62 62
     dictType *type;
  63
+#ifdef _WIN32
  64
+    size_t size;
  65
+    size_t sizemask;
  66
+    size_t used;
  67
+#else    
63 68
     unsigned long size;
64 69
     unsigned long sizemask;
65 70
     unsigned long used;
  71
+#endif
66 72
     void *privdata;
67 73
 } dict;
68 74
 
@@ -113,7 +119,11 @@ typedef struct dictIterator {
113 119
 /* API */
114 120
 static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
115 121
 static dict *dictCreate(dictType *type, void *privDataPtr);
  122
+#ifdef _WIN32
  123
+static int dictExpand(dict *ht, size_t size);
  124
+#else
116 125
 static int dictExpand(dict *ht, unsigned long size);
  126
+#endif
117 127
 static int dictAdd(dict *ht, void *key, void *val);
118 128
 static int dictReplace(dict *ht, void *key, void *val);
119 129
 static int dictDelete(dict *ht, const void *key);
90  deps/hiredis/hiredis.c
@@ -31,7 +31,9 @@
31 31
 
32 32
 #include <string.h>
33 33
 #include <stdlib.h>
34  
-#include <unistd.h>
  34
+#ifndef _WIN32
  35
+  #include <unistd.h>
  36
+#endif
35 37
 #include <assert.h>
36 38
 #include <errno.h>
37 39
 #include <ctype.h>
@@ -296,7 +298,11 @@ static int processBulkItem(redisReader *r) {
296 298
     redisReadTask *cur = &(r->rstack[r->ridx]);
297 299
     void *obj = NULL;
298 300
     char *p, *s;
  301
+#ifdef _WIN32
  302
+    long long len;
  303
+#else
299 304
     long len;
  305
+#endif
300 306
     unsigned long bytelen;
301 307
     int success = 0;
302 308
 
@@ -316,10 +322,10 @@ static int processBulkItem(redisReader *r) {
316 322
             success = 1;
317 323
         } else {
318 324
             /* Only continue when the buffer contains the entire bulk item. */
319  
-            bytelen += len+2; /* include \r\n */
  325
+            bytelen += (unsigned long)len+2; /* include \r\n */
320 326
             if (r->pos+bytelen <= r->len) {
321 327
                 if (r->fn && r->fn->createString)
322  
-                    obj = r->fn->createString(cur,s+2,len);
  328
+                    obj = r->fn->createString(cur,s+2,(size_t)len);
323 329
                 else
324 330
                     obj = (void*)REDIS_REPLY_STRING;
325 331
                 success = 1;
@@ -343,7 +349,11 @@ static int processMultiBulkItem(redisReader *r) {
343 349
     redisReadTask *cur = &(r->rstack[r->ridx]);
344 350
     void *obj;
345 351
     char *p;
  352
+#ifdef _WIN32
  353
+    long long elements;
  354
+#else
346 355
     long elements;
  356
+#endif
347 357
     int root = 0;
348 358
 
349 359
     /* Set error for nested multi bulks with depth > 1 */
@@ -365,13 +375,13 @@ static int processMultiBulkItem(redisReader *r) {
365 375
             moveToNextTask(r);
366 376
         } else {
367 377
             if (r->fn && r->fn->createArray)
368  
-                obj = r->fn->createArray(cur,elements);
  378
+                obj = r->fn->createArray(cur,(int)elements);
369 379
             else
370 380
                 obj = (void*)REDIS_REPLY_ARRAY;
371 381
 
372 382
             /* Modify task stack when there are more than 0 elements. */
373 383
             if (elements > 0) {
374  
-                cur->elements = elements;
  384
+                cur->elements = (int)elements;
375 385
                 cur->obj = obj;
376 386
                 r->ridx++;
377 387
                 r->rstack[r->ridx].type = -1;
@@ -596,7 +606,7 @@ static int intlen(int i) {
596 606
 /* Helper function for redisvFormatCommand(). */
597 607
 static void addArgument(sds a, char ***argv, int *argc, int *totlen) {
598 608
     (*argc)++;
599  
-    if ((*argv = realloc(*argv, sizeof(char*)*(*argc))) == NULL) redisOOM();
  609
+    if ((*argv = (char **)realloc(*argv, sizeof(char*)*(*argc))) == NULL) redisOOM();
600 610
     if (totlen) *totlen = *totlen+1+intlen(sdslen(a))+2+sdslen(a)+2;
601 611
     (*argv)[(*argc)-1] = a;
602 612
 }
@@ -697,7 +707,11 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
697 707
                     }
698 708
 
699 709
                     /* Consume and discard vararg */
  710
+#ifdef _WIN32
  711
+                    va_arg(ap,void *);
  712
+#else
700 713
                     va_arg(ap,void);
  714
+#endif
701 715
                 }
702 716
             }
703 717
             touched = 1;
@@ -717,11 +731,15 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
717 731
     totlen += 1+intlen(argc)+2;
718 732
 
719 733
     /* Build the command at protocol level */
720  
-    cmd = malloc(totlen+1);
  734
+    cmd = (char *)malloc(totlen+1);
721 735
     if (!cmd) redisOOM();
722 736
     pos = sprintf(cmd,"*%d\r\n",argc);
723 737
     for (j = 0; j < argc; j++) {
  738
+#ifdef _WIN32
  739
+        pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)sdslen(argv[j]));
  740
+#else
724 741
         pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(argv[j]));
  742
+#endif
725 743
         memcpy(cmd+pos,argv[j],sdslen(argv[j]));
726 744
         pos += sdslen(argv[j]);
727 745
         sdsfree(argv[j]);
@@ -780,7 +798,11 @@ int redisFormatCommandArgv(char **target, int argc, const char **argv, const siz
780 798
     pos = sprintf(cmd,"*%d\r\n",argc);
781 799
     for (j = 0; j < argc; j++) {
782 800
         len = argvlen ? argvlen[j] : strlen(argv[j]);
  801
+#ifdef _WIN32
  802
+        pos += sprintf(cmd+pos,"$%llu\r\n",(unsigned long long)len);
  803
+#else
783 804
         pos += sprintf(cmd+pos,"$%zu\r\n",len);
  805
+#endif
784 806
         memcpy(cmd+pos,argv[j],len);
785 807
         pos += len;
786 808
         cmd[pos++] = '\r';
@@ -815,7 +837,11 @@ static redisContext *redisContextInit(void) {
815 837
 
816 838
 void redisFree(redisContext *c) {
817 839
     if (c->fd > 0)
  840
+#ifdef _WIN32
  841
+        closesocket(c->fd);
  842
+#else
818 843
         close(c->fd);
  844
+#endif
819 845
     if (c->errstr != NULL)
820 846
         sdsfree(c->errstr);
821 847
     if (c->obuf != NULL)
@@ -870,6 +896,21 @@ redisContext *redisConnectUnixNonBlock(const char *path) {
870 896
     return c;
871 897
 }
872 898
 
  899
+/* initializers if caller handles connection */
  900
+redisContext *redisConnected() {
  901
+    redisContext *c = redisContextInit();
  902
+    c->fd = -1;
  903
+    c->flags |= REDIS_BLOCK;
  904
+    return c;
  905
+}
  906
+
  907
+redisContext *redisConnectedNonBlock() {
  908
+    redisContext *c = redisContextInit();
  909
+    c->fd = -1;
  910
+    c->flags &= ~REDIS_BLOCK;
  911
+    return c;
  912
+}
  913
+
873 914
 /* Set read/write timeout on a blocking socket. */
874 915
 int redisSetTimeout(redisContext *c, struct timeval tv) {
875 916
     if (c->flags & REDIS_BLOCK)
@@ -902,7 +943,16 @@ static void __redisCreateReplyReader(redisContext *c) {
902 943
  * see if there is a reply available. */
903 944
 int redisBufferRead(redisContext *c) {
904 945
     char buf[2048];
  946
+#ifdef _WIN32
  947
+    int nread = recv((SOCKET)c->fd,buf,sizeof(buf),0);
  948
+    if (nread == -1) {
  949
+        errno = WSAGetLastError();
  950
+        if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK))
  951
+            errno = EAGAIN;
  952
+    }
  953
+#else
905 954
     int nread = read(c->fd,buf,sizeof(buf));
  955
+#endif
906 956
     if (nread == -1) {
907 957
         if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
908 958
             /* Try again later */
@@ -921,6 +971,23 @@ int redisBufferRead(redisContext *c) {
921 971
     return REDIS_OK;
922 972
 }
923 973
 
  974
+/* Use this function if the caller has already read the data. It will
  975
+ * feed bytes to the reply parser.
  976
+ *
  977
+ * After this function is called, you may use redisContextReadReply to
  978
+ * see if there is a reply available. */
  979
+int redisBufferReadDone(redisContext *c, char *buf, int nread) {
  980
+    if (nread == 0) {
  981
+        __redisSetError(c,REDIS_ERR_EOF,
  982
+            sdsnew("Server closed the connection"));
  983
+        return REDIS_ERR;
  984
+    } else {
  985
+        __redisCreateReplyReader(c);
  986
+        redisReplyReaderFeed(c->reader,buf,nread);
  987
+    }
  988
+    return REDIS_OK;
  989
+}
  990
+
924 991
 /* Write the output buffer to the socket.
925 992
  *
926 993
  * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was
@@ -933,7 +1000,16 @@ int redisBufferRead(redisContext *c) {
933 1000
 int redisBufferWrite(redisContext *c, int *done) {
934 1001
     int nwritten;
935 1002
     if (sdslen(c->obuf) > 0) {
  1003
+#ifdef _WIN32
  1004
+        nwritten = send((SOCKET)c->fd,c->obuf,sdslen(c->obuf),0);
  1005
+        if (nwritten == -1) {
  1006
+            errno = WSAGetLastError();
  1007
+            if ((errno == ENOENT) || (errno == WSAEWOULDBLOCK))
  1008
+                errno = EAGAIN;
  1009
+        }
  1010
+#else
936 1011
         nwritten = write(c->fd,c->obuf,sdslen(c->obuf));
  1012
+#endif
937 1013
         if (nwritten == -1) {
938 1014
             if (errno == EAGAIN && !(c->flags & REDIS_BLOCK)) {
939 1015
                 /* Try again later */
20  deps/hiredis/hiredis.h
@@ -33,7 +33,20 @@
33 33
 #define __HIREDIS_H
34 34
 #include <stdio.h> /* for size_t */
35 35
 #include <stdarg.h> /* for va_list */
  36
+#ifndef _WIN32
36 37
 #include <sys/time.h> /* for struct timeval */
  38
+#endif
  39
+#ifdef _WIN32
  40
+    #ifndef FD_SETSIZE
  41
+      #define FD_SETSIZE 16000
  42
+    #endif
  43
+    #include <winsock2.h>
  44
+    #include <windows.h>
  45
+
  46
+    #ifndef va_copy
  47
+      #define va_copy(d,s) d = (s)
  48
+    #endif
  49
+#endif
37 50
 
38 51
 #define HIREDIS_MAJOR 0
39 52
 #define HIREDIS_MINOR 9
@@ -117,7 +130,11 @@ struct redisContext; /* need forward declaration of redisContext */
117 130
 
118 131
 /* Context for a connection to Redis */
119 132
 typedef struct redisContext {
  133
+#ifdef _WIN32
  134
+    SOCKET fd;
  135
+#else
120 136
     int fd;
  137
+#endif
121 138
     int flags;
122 139
     char *obuf; /* Write buffer */
123 140
     int err; /* Error flags, 0 when there is no error */
@@ -149,11 +166,14 @@ redisContext *redisConnectNonBlock(const char *ip, int port);
149 166
 redisContext *redisConnectUnix(const char *path);
150 167
 redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv);
151 168
 redisContext *redisConnectUnixNonBlock(const char *path);
  169
+redisContext *redisConnected();
  170
+redisContext *redisConnectedNonBlock();
152 171
 int redisSetTimeout(redisContext *c, struct timeval tv);
153 172
 int redisSetReplyObjectFunctions(redisContext *c, redisReplyObjectFunctions *fn);
154 173
 void redisFree(redisContext *c);
155 174
 int redisBufferRead(redisContext *c);
156 175
 int redisBufferWrite(redisContext *c, int *done);
  176
+int redisBufferReadDone(redisContext *c, char *buf, int nread);
157 177
 
158 178
 /* In a blocking context, this function first checks if there are unconsumed
159 179
  * replies to return and returns one if so. Otherwise, it flushes the output
180  deps/hiredis/net.c
@@ -32,6 +32,14 @@
32 32
 
33 33
 #include "fmacros.h"
34 34
 #include <sys/types.h>
  35
+#ifdef _WIN32
  36
+  #ifndef FD_SETSIZE
  37
+    #define FD_SETSIZE 16000
  38
+  #endif
  39
+  #include "winsock2.h"
  40
+  #include "windows.h"
  41
+  #define socklen_t int
  42
+#else
35 43
 #include <sys/socket.h>
36 44
 #include <sys/select.h>
37 45
 #include <sys/un.h>
@@ -39,9 +47,11 @@
39 47
 #include <netinet/tcp.h>
40 48
 #include <arpa/inet.h>
41 49
 #include <unistd.h>
  50
+#include <netdb.h>
  51
+#endif
42 52
 #include <fcntl.h>
43 53
 #include <string.h>
44  
-#include <netdb.h>
  54
+
45 55
 #include <errno.h>
46 56
 #include <stdarg.h>
47 57
 #include <stdio.h>
@@ -52,6 +62,31 @@
52 62
 /* Forward declaration */
53 63
 void __redisSetError(redisContext *c, int type, sds err);
54 64
 
  65
+#ifdef _WIN32
  66
+static int redisCreateSocket(redisContext *c, int type) {
  67
+    SOCKET s;
  68
+    int on=1;
  69
+
  70
+    s = socket(type, SOCK_STREAM, IPPROTO_TCP);
  71
+    if (s == INVALID_SOCKET) {
  72
+        __redisSetError(c,REDIS_ERR_IO,sdscatprintf(sdsempty(), "socket error: %d\n", WSAGetLastError()));
  73
+        return REDIS_ERR;
  74
+    }
  75
+    if (type == AF_INET) {
  76
+        LINGER l;
  77
+        l.l_onoff = 1;
  78
+        l.l_linger = 2;
  79
+        setsockopt(s, SOL_SOCKET, SO_LINGER, (const char *) &l, sizeof(l));
  80
+
  81
+        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *) &on, sizeof(on)) == -1) {
  82
+            __redisSetError(c,REDIS_ERR_IO,NULL);
  83
+            closesocket(s);
  84
+            return REDIS_ERR;
  85
+        }
  86
+    }
  87
+    return (int)s;
  88
+}
  89
+#else
55 90
 static int redisCreateSocket(redisContext *c, int type) {
56 91
     int s, on = 1;
57 92
     if ((s = socket(type, SOCK_STREAM, 0)) == -1) {
@@ -67,7 +102,31 @@ static int redisCreateSocket(redisContext *c, int type) {
67 102
     }
68 103
     return s;
69 104
 }
  105
+#endif
70 106
 
  107
+
  108
+#ifdef _WIN32
  109
+static int redisSetBlocking(redisContext *c, int fd, int blocking) {
  110
+    /* If iMode = 0, blocking is enabled; */
  111
+    /* If iMode != 0, non-blocking mode is enabled. */
  112
+    u_long flags;
  113
+
  114
+    if (blocking)
  115
+        flags = (u_long)0;
  116
+    else
  117
+        flags = (u_long)1;
  118
+
  119
+    if (ioctlsocket((SOCKET)fd, FIONBIO, &flags) == SOCKET_ERROR) {
  120
+        errno = WSAGetLastError();
  121
+        __redisSetError(c,REDIS_ERR_IO,
  122
+            sdscatprintf(sdsempty(), "ioctlsocket(FIONBIO): %d\n", errno));
  123
+        closesocket(fd);
  124
+        return REDIS_ERR;
  125
+    };
  126
+    return REDIS_OK;
  127
+}
  128
+
  129
+#else
71 130
 static int redisSetBlocking(redisContext *c, int fd, int blocking) {
72 131
     int flags;
73 132
 
@@ -94,7 +153,20 @@ static int redisSetBlocking(redisContext *c, int fd, int blocking) {
94 153
     }
95 154
     return REDIS_OK;
96 155
 }
  156
+#endif
97 157
 
  158
+#ifdef _WIN32
  159
+static int redisSetTcpNoDelay(redisContext *c, int fd) {
  160
+    int yes = 1;
  161
+    if (setsockopt((SOCKET)fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&yes, sizeof(yes)) == -1) {
  162
+        __redisSetError(c,REDIS_ERR_IO,
  163
+            sdscatprintf(sdsempty(), "setsockopt(TCP_NODELAY): %d", (int)GetLastError()));
  164
+        closesocket(fd);
  165
+        return REDIS_ERR;
  166
+    }
  167
+    return REDIS_OK;
  168
+}
  169
+#else
98 170
 static int redisSetTcpNoDelay(redisContext *c, int fd) {
99 171
     int yes = 1;
100 172
     if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) {
@@ -105,6 +177,7 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
105 177
     }
106 178
     return REDIS_OK;
107 179
 }
  180
+#endif
108 181
 
109 182
 static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) {
110 183
     struct timeval to;
@@ -121,35 +194,62 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
121 194
 
122 195
     if (errno == EINPROGRESS) {
123 196
         FD_ZERO(&wfd);
  197
+#ifdef _WIN32
  198
+        FD_SET((SOCKET)fd, &wfd);
  199
+#else
124 200
         FD_SET(fd, &wfd);
  201
+#endif
125 202
 
126 203
         if (select(FD_SETSIZE, NULL, &wfd, NULL, toptr) == -1) {
127 204
             __redisSetError(c,REDIS_ERR_IO,
128 205
                 sdscatprintf(sdsempty(), "select(2): %s", strerror(errno)));
  206
+#ifdef _WIN32
  207
+            closesocket(fd);
  208
+#else
129 209
             close(fd);
  210
+#endif
130 211
             return REDIS_ERR;
131 212
         }
132 213
 
133 214
         if (!FD_ISSET(fd, &wfd)) {
  215
+#ifdef _WIN32
  216
+            errno = WSAGetLastError();
  217
+            __redisSetError(c,REDIS_ERR_IO,NULL);
  218
+            closesocket(fd);
  219
+#else
134 220
             errno = ETIMEDOUT;
135 221
             __redisSetError(c,REDIS_ERR_IO,NULL);
136 222
             close(fd);
  223
+#endif
137 224
             return REDIS_ERR;
138 225
         }
139 226
 
140 227
         err = 0;
141 228
         errlen = sizeof(err);
  229
+#ifdef _WIN32
  230
+        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen) == SOCKET_ERROR) {
  231
+            __redisSetError(c,REDIS_ERR_IO,
  232
+                sdscatprintf(sdsempty(), "getsockopt(SO_ERROR): %d", WSAGetLastError()));
  233
+            closesocket(fd);
  234
+            return REDIS_ERR;
  235
+        }
  236
+#else
142 237
         if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
143 238
             __redisSetError(c,REDIS_ERR_IO,
144 239
                 sdscatprintf(sdsempty(), "getsockopt(SO_ERROR): %s", strerror(errno)));
145 240
             close(fd);
146 241
             return REDIS_ERR;
147 242
         }
  243
+#endif
148 244
 
149 245
         if (err) {
150 246
             errno = err;
151 247
             __redisSetError(c,REDIS_ERR_IO,NULL);
  248
+#ifdef _WIN32
  249
+            closesocket(fd);
  250
+#else
152 251
             close(fd);
  252
+#endif
153 253
             return REDIS_ERR;
154 254
         }
155 255
 
@@ -157,10 +257,29 @@ static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *
157 257
     }
158 258
 
159 259
     __redisSetError(c,REDIS_ERR_IO,NULL);
  260
+#ifdef _WIN32
  261
+    closesocket(fd);
  262
+#else
160 263
     close(fd);
  264
+#endif
161 265
     return REDIS_ERR;
162 266
 }
163 267
 
  268
+#ifdef _WIN32
  269
+int redisContextSetTimeout(redisContext *c, struct timeval tv) {
  270
+    if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,(const char *)&tv,sizeof(tv)) == SOCKET_ERROR ) {
  271
+        __redisSetError(c,REDIS_ERR_IO,
  272
+            sdscatprintf(sdsempty(), "setsockopt(SO_RCVTIMEO): %d",  WSAGetLastError()));
  273
+        return REDIS_ERR;
  274
+    }
  275
+    if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,(const char *)&tv,sizeof(tv)) == SOCKET_ERROR ) {
  276
+        __redisSetError(c,REDIS_ERR_IO,
  277
+            sdscatprintf(sdsempty(), "setsockopt(SO_SNDTIMEO): %d",  WSAGetLastError()));
  278
+        return REDIS_ERR;
  279
+    }
  280
+    return REDIS_OK;
  281
+}
  282
+#else
164 283
 int redisContextSetTimeout(redisContext *c, struct timeval tv) {
165 284
     if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) {
166 285
         __redisSetError(c,REDIS_ERR_IO,
@@ -174,7 +293,57 @@ int redisContextSetTimeout(redisContext *c, struct timeval tv) {
174 293
     }
175 294
     return REDIS_OK;
176 295
 }
  296
+#endif
177 297
 
  298
+#ifdef _WIN32
  299
+int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout) {
  300
+    int s;
  301
+    int blocking = (c->flags & REDIS_BLOCK);
  302
+    struct sockaddr_in sa;
  303
+    unsigned long inAddress;
  304
+
  305
+    if ((s = redisCreateSocket(c,AF_INET)) < 0)
  306
+        return REDIS_ERR;
  307
+
  308
+    sa.sin_family = AF_INET;
  309
+    sa.sin_port = htons(port);
  310
+    if (redisSetTcpNoDelay(c,s) != REDIS_OK)
  311
+        return REDIS_ERR;
  312
+
  313
+    inAddress = inet_addr(addr);
  314
+    if (inAddress == INADDR_NONE || inAddress == INADDR_ANY) {
  315
+        struct hostent *he;
  316
+
  317
+        he = gethostbyname(addr);
  318
+        if (he == NULL) {
  319
+            __redisSetError(c,REDIS_ERR_OTHER,
  320
+                sdscatprintf(sdsempty(),"can't resolve: %s\n", addr));
  321
+            closesocket(s);
  322
+            return REDIS_ERR;;
  323
+        }
  324
+        memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
  325
+    }
  326
+    else {
  327
+        sa.sin_addr.s_addr = inAddress;
  328
+    }
  329
+
  330
+    if (connect((SOCKET)s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
  331
+        errno = WSAGetLastError();
  332
+        if ((errno == WSAEINVAL) || (errno == WSAEWOULDBLOCK))
  333
+            errno = EINPROGRESS;
  334
+        if (errno == EINPROGRESS && !blocking) {
  335
+            /* This is ok. */
  336
+        } else {
  337
+            if (redisContextWaitReady(c,s,timeout) != REDIS_OK)
  338
+                return REDIS_ERR;
  339
+        }
  340
+    }
  341
+
  342
+    c->fd = s;
  343
+    c->flags |= REDIS_CONNECTED;
  344
+    return REDIS_OK;
  345
+}
  346
+#else
178 347
 int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct timeval *timeout) {
179 348
     int s;
180 349
     int blocking = (c->flags & REDIS_BLOCK);
@@ -220,8 +389,16 @@ int redisContextConnectTcp(redisContext *c, const char *addr, int port, struct t
220 389
     c->flags |= REDIS_CONNECTED;
221 390
     return REDIS_OK;
222 391
 }
  392
+#endif
223 393
 
224 394
 int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *timeout) {
  395
+#ifdef _WIN32
  396
+    (void) timeout;
  397
+    __redisSetError(c,REDIS_ERR_IO,
  398
+        sdscatprintf(sdsempty(),"Unix sockets are not suported on Windows platform. (%s)\n", path));
  399
+
  400
+    return REDIS_ERR;
  401
+#else
225 402
     int s;
226 403
     int blocking = (c->flags & REDIS_BLOCK);
227 404
     struct sockaddr_un sa;
@@ -249,4 +426,5 @@ int redisContextConnectUnix(redisContext *c, const char *path, struct timeval *t
249 426
     c->fd = s;
250 427
     c->flags |= REDIS_CONNECTED;
251 428
     return REDIS_OK;
  429
+#endif
252 430
 }
9  deps/hiredis/sds.h
@@ -34,6 +34,11 @@
34 34
 #include <sys/types.h>
35 35
 #include <stdarg.h>
36 36
 
  37
+#ifdef _WIN32
  38
+  #define inline __inline
  39
+  #define va_copy(d,s) d = (s)
  40
+#endif
  41
+
37 42
 typedef char *sds;
38 43
 
39 44
 struct sdshdr {
@@ -43,12 +48,12 @@ struct sdshdr {
43 48
 };
44 49
 
45 50
 static inline size_t sdslen(const sds s) {
46  
-    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
  51
+    struct sdshdr *sh = (struct sdshdr *)(s-(sizeof(struct sdshdr)));
47 52
     return sh->len;
48 53
 }
49 54
 
50 55
 static inline size_t sdsavail(const sds s) {
51  
-    struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
  56
+    struct sdshdr *sh = (struct sdshdr *)(s-(sizeof(struct sdshdr)));
52 57
     return sh->free;
53 58
 }
54 59
 
246  deps/linenoise/linenoise.c
@@ -82,24 +82,31 @@
82 82
  * 
83 83
  */
84 84
 
  85
+#ifndef _WIN32
85 86
 #include <termios.h>
86 87
 #include <unistd.h>
  88
+#include <sys/ioctl.h>
  89
+#endif
87 90
 #include <stdlib.h>
88 91
 #include <stdio.h>
89 92
 #include <errno.h>
90 93
 #include <string.h>
91 94
 #include <stdlib.h>
92 95
 #include <sys/types.h>
93  
-#include <sys/ioctl.h>
94  
-#include <unistd.h>
95 96
 #include "linenoise.h"
  97
+#ifdef _WIN32
  98
+  #include "../../src/win32fixes.h"
  99
+  #define REDIS_NOTUSED(V) ((void) V)
  100
+#endif
96 101
 
97 102
 #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
98 103
 #define LINENOISE_MAX_LINE 4096
99 104
 static char *unsupported_term[] = {"dumb","cons25",NULL};
100 105
 static linenoiseCompletionCallback *completionCallback = NULL;
101 106
 
  107
+#ifndef _WIN32
102 108
 static struct termios orig_termios; /* in order to restore at exit */
  109
+#endif
103 110
 static int rawmode = 0; /* for atexit() function to check if restore is needed*/
104 111
 static int atexit_registered = 0; /* register atexit just 1 time */
105 112
 static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN;
@@ -109,13 +116,141 @@ char **history = NULL;
109 116
 static void linenoiseAtExit(void);
110 117
 int linenoiseHistoryAdd(const char *line);
111 118
 
  119
+#ifdef _WIN32
  120
+#ifndef STDIN_FILENO
  121
+  #define STDIN_FILENO (_fileno(stdin))
  122
+#endif
  123
+
  124
+HANDLE hOut;
  125
+HANDLE hIn;
  126
+DWORD consolemode;
  127
+
  128
+static int win32read(char *c) {
  129
+
  130
+    DWORD foo;
  131
+    INPUT_RECORD b;
  132
+    KEY_EVENT_RECORD e;
  133
+
  134
+    while (1) {
  135
+        if (!ReadConsoleInput(hIn, &b, 1, &foo)) return 0;
  136
+        if (!foo) return 0;
  137
+
  138
+        if (b.EventType == KEY_EVENT && b.Event.KeyEvent.bKeyDown) {
  139
+
  140
+            e = b.Event.KeyEvent;
  141
+            *c = b.Event.KeyEvent.uChar.AsciiChar;
  142
+
  143
+            //if (e.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
  144
+                /* Alt+key ignored */
  145
+            //} else
  146
+            if (e.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) {
  147
+
  148
+                /* Ctrl+Key */
  149
+                switch (*c) {
  150
+                    case 'D':
  151
+                        *c = 4;
  152
+                        return 1;
  153
+                    case 'C':
  154
+                        *c = 3;
  155
+                        return 1;
  156
+                    case 'H':
  157
+                        *c = 8;
  158
+                        return 1;
  159
+                    case 'T':
  160
+                        *c = 20;
  161
+                        return 1;
  162
+                    case 'B': /* ctrl-b, left_arrow */
  163
+                        *c = 2;
  164
+                        return 1;
  165
+                    case 'F': /* ctrl-f right_arrow*/
  166
+                        *c = 6;
  167
+                        return 1;
  168
+                    case 'P': /* ctrl-p up_arrow*/
  169
+                        *c = 16;
  170
+                        return 1;
  171
+                    case 'N': /* ctrl-n down_arrow*/
  172
+                        *c = 14;
  173
+                        return 1;
  174
+                    case 'U': /* Ctrl+u, delete the whole line. */
  175
+                        *c = 21;
  176
+                        return 1;
  177
+                    case 'K': /* Ctrl+k, delete from current to end of line. */
  178
+                        *c = 11;
  179
+                        return 1;
  180
+                    case 'A': /* Ctrl+a, go to the start of the line */
  181
+                        *c = 1;
  182
+                        return 1;
  183
+                    case 'E': /* ctrl+e, go to the end of the line */
  184
+                        *c = 5;
  185
+                        return 1;
  186
+                }
  187
+
  188
+                /* Other Ctrl+KEYs ignored */
  189
+            } else {
  190
+
  191
+                switch (e.wVirtualKeyCode) {
  192
+
  193
+                    case VK_ESCAPE: /* ignore - send ctrl-c, will return -1 */
  194
+                        *c = 3;
  195
+                        return 1;
  196
+                    case VK_RETURN:  /* enter */
  197
+                        *c = 13;
  198
+                        return 1;
  199
+                    case VK_LEFT:   /* left */
  200
+                        *c = 2;
  201
+                        return 1;
  202
+                    case VK_RIGHT: /* right */
  203
+                        *c = 6;
  204
+                        return 1;
  205
+                    case VK_UP:   /* up */
  206
+                        *c = 16;
  207
+                        return 1;
  208
+                    case VK_DOWN:  /* down */
  209
+                        *c = 14;
  210
+                        return 1;
  211
+                    case VK_HOME:
  212
+                        *c = 1;
  213
+                        return 1;
  214
+                    case VK_END:
  215
+                        *c = 5;
  216
+                        return 1;
  217
+                    case VK_BACK:
  218
+                        *c = 8;
  219
+                        return 1;
  220
+                    case VK_DELETE:
  221
+                        *c = 127;
  222
+                        return 1;
  223
+                    default:
  224
+                        if (*c) return 1;
  225
+                }
  226
+            }
  227
+        }
  228
+    }
  229
+
  230
+    return -1; /* Makes compiler happy */
  231
+}
  232
+
  233
+#ifdef __STRICT_ANSI__
  234
+char *strdup(const char *s) {
  235
+    size_t l = strlen(s)+1;
  236
+    char *p = malloc(l);
  237
+
  238
+    memcpy(p,s,l);
  239
+    return p;
  240
+}
  241
+#endif /*   __STRICT_ANSI__   */
  242
+
  243
+#endif /*   _WIN32    */
  244
+
112 245
 static int isUnsupportedTerm(void) {
  246
+#ifndef _WIN32
113 247
     char *term = getenv("TERM");
114 248
     int j;
115 249
 
116 250
     if (term == NULL) return 0;
117 251
     for (j = 0; unsupported_term[j]; j++)
118 252
         if (!strcasecmp(term,unsupported_term[j])) return 1;
  253
+#endif
119 254
     return 0;
120 255
 }
121 256
 
@@ -130,6 +265,7 @@ static void freeHistory(void) {
130 265
 }
131 266
 
132 267
 static int enableRawMode(int fd) {
  268
+#ifndef _WIN32
133 269
     struct termios raw;
134 270
 
135 271
     if (!isatty(STDIN_FILENO)) goto fatal;
@@ -157,6 +293,37 @@ static int enableRawMode(int fd) {
157 293
     /* put terminal in raw mode after flushing */
158 294
     if (tcsetattr(fd,TCSAFLUSH,&raw) < 0) goto fatal;
159 295
     rawmode = 1;
  296
+#else
  297
+    REDIS_NOTUSED(fd);
  298
+
  299
+    if (!atexit_registered) {
  300
+        /* Init windows console handles only once */
  301
+        hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  302
+        if (hOut==INVALID_HANDLE_VALUE) goto fatal;
  303
+
  304
+        if (!GetConsoleMode(hOut, &consolemode)) {
  305
+            CloseHandle(hOut);
  306
+            errno = ENOTTY;
  307
+            return -1;
  308
+        };
  309
+
  310
+        hIn = GetStdHandle(STD_INPUT_HANDLE);
  311
+        if (hIn == INVALID_HANDLE_VALUE) {
  312
+            CloseHandle(hOut);
  313
+            errno = ENOTTY;
  314
+            return -1;
  315
+        }
  316
+
  317
+        GetConsoleMode(hIn, &consolemode);
  318
+        SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT);
  319
+
  320
+        /* Cleanup them at exit */
  321
+        atexit(linenoiseAtExit);
  322
+        atexit_registered = 1;
  323
+    }
  324
+
  325
+    rawmode = 1;
  326
+#endif
160 327
     return 0;
161 328
 
162 329
 fatal:
@@ -165,26 +332,49 @@ static int enableRawMode(int fd) {
165 332
 }
166 333
 
167 334
 static void disableRawMode(int fd) {
  335
+#ifdef _WIN32
  336
+    REDIS_NOTUSED(fd);
  337
+    rawmode = 0;
  338
+#else
168 339
     /* Don't even check the return value as it's too late. */
169 340
     if (rawmode && tcsetattr(fd,TCSAFLUSH,&orig_termios) != -1)
170 341
         rawmode = 0;
  342
+#endif
171 343
 }
172 344
 
173 345
 /* At exit we'll try to fix the terminal to the initial conditions. */
174 346
 static void linenoiseAtExit(void) {
  347
+#ifdef _WIN32
  348
+    SetConsoleMode(hIn, consolemode);
  349
+    CloseHandle(hOut);
  350
+    CloseHandle(hIn);
  351
+#else
175 352
     disableRawMode(STDIN_FILENO);
  353
+#endif
176 354
     freeHistory();
177 355
 }
178 356
 
179 357
 static int getColumns(void) {
  358
+#ifdef _WIN32
  359
+    CONSOLE_SCREEN_BUFFER_INFO b;
  360
+
  361
+    if (!GetConsoleScreenBufferInfo(hOut, &b)) return 80;
  362
+    return b.srWindow.Right - b.srWindow.Left;
  363
+#else
180 364
     struct winsize ws;
181 365
 
182 366
     if (ioctl(1, TIOCGWINSZ, &ws) == -1) return 80;
183 367
     return ws.ws_col;
  368
+#endif
184 369
 }
185 370
 
186 371
 static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_t pos, size_t cols) {
187 372
     char seq[64];
  373
+#ifdef _WIN32
  374
+    DWORD pl, bl, w;
  375
+    CONSOLE_SCREEN_BUFFER_INFO b;
  376
+    COORD coord;
  377
+#endif
188 378
     size_t plen = strlen(prompt);
189 379
     
190 380
     while((plen+pos) >= cols) {
@@ -196,6 +386,7 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
196 386
         len--;
197 387
     }
198 388
 
  389
+#ifndef _WIN32
199 390
     /* Cursor to left edge */
200 391
     snprintf(seq,64,"\x1b[0G");
201 392
     if (write(fd,seq,strlen(seq)) == -1) return;
@@ -208,6 +399,27 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
208 399
     /* Move cursor to original position. */
209 400
     snprintf(seq,64,"\x1b[0G\x1b[%dC", (int)(pos+plen));
210 401
     if (write(fd,seq,strlen(seq)) == -1) return;
  402
+#else
  403
+
  404
+    REDIS_NOTUSED(seq);
  405
+    REDIS_NOTUSED(fd);
  406
+
  407
+    /* Get buffer console info */
  408
+    if (!GetConsoleScreenBufferInfo(hOut, &b)) return;
  409
+    /* Erase Line */
  410
+    coord.X = 0;
  411
+    coord.Y = b.dwCursorPosition.Y;
  412
+	FillConsoleOutputCharacterA(hOut, ' ', b.dwSize.X, coord, &w);
  413
+    /*  Cursor to the left edge */
  414
+    SetConsoleCursorPosition(hOut, coord);
  415
+    /* Write the prompt and the current buffer content */
  416
+    WriteConsole(hOut, prompt, plen, &pl, NULL);
  417
+    WriteConsole(hOut, buf, len, &bl, NULL);
  418
+    /* Move cursor to original position. */
  419
+    coord.X = (int)(pos+plen);
  420
+    coord.Y = b.dwCursorPosition.Y;
  421
+    SetConsoleCursorPosition(hOut, coord);
  422
+#endif
211 423
 }
212 424
 
213 425
 static void beep() {
@@ -290,6 +502,9 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
290 502
     size_t len = 0;
291 503
     size_t cols = getColumns();
292 504
     int history_index = 0;
  505
+#ifdef _WIN32
  506
+    DWORD foo;
  507
+#endif
293 508
 
294 509
     buf[0] = '\0';
295 510
     buflen--; /* Make sure there is always space for the nulterm */
@@ -298,13 +513,21 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
298 513
      * initially is just an empty string. */
299 514
     linenoiseHistoryAdd("");
300 515
     
  516
+#ifdef _WIN32
  517
+    if (!WriteConsole(hOut, prompt, plen, &foo, NULL)) return -1;
  518
+#else
301 519
     if (write(fd,prompt,plen) == -1) return -1;
  520
+#endif
302 521
     while(1) {
303 522
         char c;
304 523
         int nread;
305 524
         char seq[2], seq2[2];
306 525
 
  526
+#ifdef _WIN32
  527
+        nread = win32read(&c);
  528
+#else
307 529
         nread = read(fd,&c,1);
  530
+#endif
308 531
         if (nread <= 0) return len;
309 532
 
310 533
         /* Only autocomplete when the callback is set. It returns < 0 when
@@ -327,6 +550,17 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
327 550
             errno = EAGAIN;
328 551
             return -1;
329 552
         case 127:   /* backspace */
  553
+#ifdef _WIN32
  554
+            /* delete in _WIN32*/
  555
+            /* win32read() will send 127 for DEL and 8 for BS and Ctrl-H */
  556
+            if (pos < len && len > 0) {
  557
+                memmove(buf+pos,buf+pos+1,len-pos);
  558
+                len--;
  559
+                buf[len] = '\0';
  560
+                refreshLine(fd,prompt,buf,len,pos,cols);
  561
+            }
  562
+            break;
  563
+#endif
330 564
         case 8:     /* ctrl-h */
331 565
             if (pos > 0 && len > 0) {
332 566
                 memmove(buf+pos-1,buf+pos,len-pos);
@@ -430,7 +664,11 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
430 664
                     if (plen+len < cols) {
431 665
                         /* Avoid a full update of the line in the
432 666
                          * trivial case. */
  667
+#ifdef _WIN32
  668
+                        if (!WriteConsole(hOut, &c, 1, &foo, NULL)) return -1;
  669
+#else
433 670
                         if (write(fd,&c,1) == -1) return -1;
  671
+#endif
434 672
                     } else {
435 673
                         refreshLine(fd,pro