mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-11 21:03:05 +08:00
+ enable "unlimited" (as in Scintilla Lib: dep. on memory and INT_MAX) undo / redo selection history
using utarray from uthash header library (https://troydhanson.github.io/uthash/index.html)
This commit is contained in:
parent
3ca370a13c
commit
98f7649aee
@ -360,6 +360,7 @@ void EditSetNewText(HWND hwnd,char* lpstrText,DWORD cbText)
|
||||
|
||||
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,1,0);
|
||||
SendMessage(hwnd,EM_EMPTYUNDOBUFFER,0,0);
|
||||
UndoRedoSelectionMap(-1,NULL);
|
||||
SendMessage(hwnd,SCI_SETSAVEPOINT,0,0);
|
||||
SendMessage(hwnd,SCI_GOTOPOS,0,0);
|
||||
SendMessage(hwnd,SCI_CHOOSECARETX,0,0);
|
||||
@ -396,6 +397,7 @@ BOOL EditConvertText(HWND hwnd,int encSource,int encDest,BOOL bSetSavePoint)
|
||||
Encoding_SciSetCodePage(hwnd,encDest);
|
||||
SendMessage(hwnd,SCI_SETUNDOCOLLECTION,1,0);
|
||||
SendMessage(hwnd,EM_EMPTYUNDOBUFFER,0,0);
|
||||
UndoRedoSelectionMap(-1,NULL);
|
||||
SendMessage(hwnd,SCI_GOTOPOS,0,0);
|
||||
SendMessage(hwnd,SCI_CHOOSECARETX,0,0);
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "SciCall.h"
|
||||
#include "resource.h"
|
||||
#include "../crypto/crypto.h"
|
||||
#include "../uthash/utarray.h"
|
||||
#include "helpers.h"
|
||||
#include "notepad3.h"
|
||||
|
||||
@ -294,6 +295,10 @@ WCHAR g_wchAppUserModelID[32] = { L'\0' };
|
||||
WCHAR g_wchWorkingDirectory[MAX_PATH] = { L'\0' };
|
||||
|
||||
|
||||
// undo / redo selections
|
||||
static UT_icd UndoRedoSelection_icd = { sizeof(UndoRedoSelection_t), NULL, NULL, NULL };
|
||||
static UT_array* UndoRedoSelectionUTArray = NULL;
|
||||
|
||||
|
||||
//Graphics for bookmark indicator
|
||||
/* XPM */
|
||||
@ -935,6 +940,15 @@ HWND InitInstance(HINSTANCE hInstance,LPSTR pszCmdLine,int nCmdShow)
|
||||
flagQuietCreate = 0;
|
||||
fKeepTitleExcerpt = 0;
|
||||
|
||||
// undo / redo selections
|
||||
if (UndoRedoSelectionUTArray != NULL) {
|
||||
utarray_clear(UndoRedoSelectionUTArray);
|
||||
utarray_free(UndoRedoSelectionUTArray);
|
||||
UndoRedoSelectionUTArray = NULL;
|
||||
}
|
||||
utarray_new(UndoRedoSelectionUTArray, &UndoRedoSelection_icd);
|
||||
utarray_reserve(UndoRedoSelectionUTArray,256);
|
||||
|
||||
// Check for /c [if no file is specified] -- even if a file is specified
|
||||
/*else */if (flagNewFromClipboard) {
|
||||
if (SendMessage(hwndEdit,SCI_CANPASTE,0,0)) {
|
||||
@ -7119,7 +7133,7 @@ void InvalidateSelections()
|
||||
int BeginSelUndoAction()
|
||||
{
|
||||
int token = -1;
|
||||
UndoRedoSelection sel = { -1 };
|
||||
UndoRedoSelection_t sel = { -1, -1, -1, -1, -1 };
|
||||
sel.selMode = (int)SendMessage(hwndEdit,SCI_GETSELECTIONMODE,0,0);
|
||||
if (sel.selMode == SC_SEL_LINES) {
|
||||
sel.anchorPos_undo = (int)SendMessage(hwndEdit,SCI_GETSELECTIONSTART,0,0);
|
||||
@ -7129,7 +7143,7 @@ int BeginSelUndoAction()
|
||||
sel.anchorPos_undo = (int)SendMessage(hwndEdit,SCI_GETANCHOR,0,0);
|
||||
sel.currPos_undo = (int)SendMessage(hwndEdit,SCI_GETCURRENTPOS,0,0);
|
||||
}
|
||||
token = UndoSelectionMap(-1, &sel);
|
||||
token = UndoRedoSelectionMap(-1, &sel);
|
||||
if (token >= 0) {
|
||||
SendMessage(hwndEdit, SCI_BEGINUNDOACTION, 0, 0);
|
||||
SendMessage(hwndEdit, SCI_ADDUNDOACTION, (WPARAM)token, 0);
|
||||
@ -7147,8 +7161,8 @@ int BeginSelUndoAction()
|
||||
void EndSelUndoAction(int token)
|
||||
{
|
||||
if (token >= 0) {
|
||||
UndoRedoSelection sel = { -1 };
|
||||
if (UndoSelectionMap(token,&sel) >= 0) {
|
||||
UndoRedoSelection_t sel = { -1, -1, -1, -1, -1 };
|
||||
if (UndoRedoSelectionMap(token,&sel) >= 0) {
|
||||
// mode should not have changed ???
|
||||
if (sel.selMode == SC_SEL_LINES) {
|
||||
sel.anchorPos_redo = (int)SendMessage(hwndEdit,SCI_GETSELECTIONSTART,0,0);
|
||||
@ -7159,7 +7173,7 @@ void EndSelUndoAction(int token)
|
||||
sel.currPos_redo = (int)SendMessage(hwndEdit,SCI_GETCURRENTPOS,0,0);
|
||||
}
|
||||
}
|
||||
UndoSelectionMap(token,&sel); // set with redo action filled
|
||||
UndoRedoSelectionMap(token,&sel); // set with redo action filled
|
||||
SendMessage(hwndEdit, SCI_ENDUNDOACTION, 0, 0);
|
||||
bModified = TRUE;
|
||||
}
|
||||
@ -7173,8 +7187,8 @@ void EndSelUndoAction(int token)
|
||||
//
|
||||
void RestoreSelectionAction(int token, DoAction doAct)
|
||||
{
|
||||
UndoRedoSelection sel = { -1 };
|
||||
if (UndoSelectionMap(token,&sel) >= 0) {
|
||||
UndoRedoSelection_t sel = { -1, -1, -1, -1, -1 };
|
||||
if (UndoRedoSelectionMap(token,&sel) >= 0) {
|
||||
// we are inside undo/redo transaction, so do delayed PostMessage() instead of SendMessage()
|
||||
int anchorPos = (doAct == UNDO ? sel.anchorPos_undo : sel.anchorPos_redo);
|
||||
int currPos = (doAct == UNDO ? sel.currPos_undo : sel.currPos_redo);
|
||||
@ -7201,34 +7215,41 @@ void RestoreSelectionAction(int token, DoAction doAct)
|
||||
// UndoSelectionMap()
|
||||
//
|
||||
//
|
||||
int UndoSelectionMap(int token, LPUndoRedoSelection selection)
|
||||
{
|
||||
static UndoRedoSelection UndoRedoMap[MAX_SELUNDO] = { { -1 } };
|
||||
static int iMapIdx = 0;
|
||||
|
||||
if (selection == NULL)
|
||||
int UndoRedoSelectionMap(int token, UndoRedoSelection_t* selection)
|
||||
{
|
||||
static unsigned int iTokenCnt = 0;
|
||||
|
||||
// indexing is unsigned
|
||||
unsigned int utoken = (token >= 0) ? (unsigned int)token : 0U;
|
||||
|
||||
if (selection == NULL) {
|
||||
// reset / clear
|
||||
if (UndoRedoSelectionUTArray != NULL) {
|
||||
utarray_clear(UndoRedoSelectionUTArray);
|
||||
utarray_init(UndoRedoSelectionUTArray,&UndoRedoSelection_icd);
|
||||
}
|
||||
iTokenCnt = 0U;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// get or set map item request ?
|
||||
if ((token >= 0) && (token < MAX_SELUNDO)) {
|
||||
if (token >= 0 && utoken < iTokenCnt) {
|
||||
if (selection->anchorPos_undo < 0) {
|
||||
// this is a get request
|
||||
*selection = UndoRedoMap[token];
|
||||
if (selection->anchorPos_undo < 0) {
|
||||
token = -1; // invalid
|
||||
}
|
||||
*selection = *(UndoRedoSelection_t*)utarray_eltptr(UndoRedoSelectionUTArray,utoken);
|
||||
}
|
||||
else {
|
||||
// this is a set request (fill redo pos)
|
||||
UndoRedoMap[token] = *selection;
|
||||
utarray_insert(UndoRedoSelectionUTArray,(void*)selection,utoken);
|
||||
}
|
||||
// don't clear map item here (token used in redo/undo again)
|
||||
}
|
||||
else if (token < 0) {
|
||||
// set map new item request
|
||||
token = (iMapIdx + 1) % MAX_SELUNDO; // round robin next
|
||||
UndoRedoMap[token] = *selection;
|
||||
iMapIdx = token; // remember map index
|
||||
utarray_insert(UndoRedoSelectionUTArray,(void*)selection,iTokenCnt);
|
||||
token = (int)iTokenCnt;
|
||||
iTokenCnt = (iTokenCnt < INT_MAX) ? (iTokenCnt + 1) : 0U; // round robin next
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@ -41,16 +41,15 @@ typedef struct np3params {
|
||||
} np3params, *LPnp3params;
|
||||
|
||||
|
||||
#define MAX_SELUNDO 1024
|
||||
typedef struct _undoSel
|
||||
{
|
||||
int selMode;
|
||||
int anchorPos_undo;
|
||||
int currPos_undo;
|
||||
int anchorPos_redo;
|
||||
int currPos_redo;
|
||||
int selMode;
|
||||
}
|
||||
UndoRedoSelection, *LPUndoRedoSelection;
|
||||
UndoRedoSelection_t;
|
||||
|
||||
typedef enum {
|
||||
UNDO = TRUE,
|
||||
@ -144,7 +143,7 @@ void InvalidateSelections();
|
||||
int BeginSelUndoAction();
|
||||
void EndSelUndoAction(int);
|
||||
void RestoreSelectionAction(int,DoAction);
|
||||
int UndoSelectionMap(int, LPUndoRedoSelection);
|
||||
int UndoRedoSelectionMap(int,UndoRedoSelection_t*);
|
||||
|
||||
|
||||
BOOL FileIO(BOOL,LPCWSTR,BOOL,int*,int*,BOOL*,BOOL*,BOOL*,BOOL);
|
||||
|
||||
20
uthash/License_BSD_revised.txt
Normal file
20
uthash/License_BSD_revised.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2005-2016, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
238
uthash/utarray.h
Normal file
238
uthash/utarray.h
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a dynamic array implementation using macros
|
||||
*/
|
||||
#ifndef UTARRAY_H
|
||||
#define UTARRAY_H
|
||||
|
||||
#define UTARRAY_VERSION 2.0.2
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <string.h> /* memset, etc */
|
||||
#include <stdlib.h> /* exit */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UTARRAY_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define UTARRAY_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef oom
|
||||
#define oom() exit(-1)
|
||||
#endif
|
||||
|
||||
typedef void (ctor_f)(void *dst, const void *src);
|
||||
typedef void (dtor_f)(void *elt);
|
||||
typedef void (init_f)(void *elt);
|
||||
typedef struct {
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
} UT_icd;
|
||||
|
||||
typedef struct {
|
||||
unsigned i,n;/* i: index of next available slot, n: num slots */
|
||||
UT_icd icd; /* initializer, copy and destructor functions */
|
||||
char *d; /* n slots of size icd->sz*/
|
||||
} UT_array;
|
||||
|
||||
#define utarray_init(a,_icd) do { \
|
||||
memset(a,0,sizeof(UT_array)); \
|
||||
(a)->icd = *(_icd); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_done(a) do { \
|
||||
if ((a)->n) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
unsigned _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
free((a)->d); \
|
||||
} \
|
||||
(a)->n=0; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_new(a,_icd) do { \
|
||||
(a) = (UT_array*)malloc(sizeof(UT_array)); \
|
||||
if ((a) == NULL) oom(); \
|
||||
utarray_init(a,_icd); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_free(a) do { \
|
||||
utarray_done(a); \
|
||||
free(a); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_reserve(a,by) do { \
|
||||
if (((a)->i+(by)) > (a)->n) { \
|
||||
char *utarray_tmp; \
|
||||
while (((a)->i+(by)) > (a)->n) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
|
||||
utarray_tmp=(char*)realloc((a)->d, (a)->n*(a)->icd.sz); \
|
||||
if (utarray_tmp == NULL) oom(); \
|
||||
(a)->d=utarray_tmp; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_push_back(a,p) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_pop_back(a) do { \
|
||||
if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
|
||||
else { (a)->i--; } \
|
||||
} while(0)
|
||||
|
||||
#define utarray_extend_back(a) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
|
||||
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_len(a) ((a)->i)
|
||||
|
||||
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
|
||||
#define _utarray_eltptr(a,j) ((a)->d + ((a)->icd.sz * (j)))
|
||||
|
||||
#define utarray_insert(a,p,j) do { \
|
||||
if ((j) > (a)->i) utarray_resize(a,j); \
|
||||
utarray_reserve(a,1); \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_inserta(a,w,j) do { \
|
||||
if (utarray_len(w) == 0) break; \
|
||||
if ((j) > (a)->i) utarray_resize(a,j); \
|
||||
utarray_reserve(a,utarray_len(w)); \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
|
||||
_utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { \
|
||||
unsigned _ut_i; \
|
||||
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
|
||||
(a)->icd.copy(_utarray_eltptr(a, (j) + _ut_i), _utarray_eltptr(w, _ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
|
||||
utarray_len(w)*((a)->icd.sz)); \
|
||||
} \
|
||||
(a)->i += utarray_len(w); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_resize(dst,num) do { \
|
||||
unsigned _ut_i; \
|
||||
if ((dst)->i > (unsigned)(num)) { \
|
||||
if ((dst)->icd.dtor) { \
|
||||
for (_ut_i = (num); _ut_i < (dst)->i; ++_ut_i) { \
|
||||
(dst)->icd.dtor(_utarray_eltptr(dst, _ut_i)); \
|
||||
} \
|
||||
} \
|
||||
} else if ((dst)->i < (unsigned)(num)) { \
|
||||
utarray_reserve(dst, (num) - (dst)->i); \
|
||||
if ((dst)->icd.init) { \
|
||||
for (_ut_i = (dst)->i; _ut_i < (unsigned)(num); ++_ut_i) { \
|
||||
(dst)->icd.init(_utarray_eltptr(dst, _ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memset(_utarray_eltptr(dst, (dst)->i), 0, (dst)->icd.sz*((num) - (dst)->i)); \
|
||||
} \
|
||||
} \
|
||||
(dst)->i = (num); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_concat(dst,src) do { \
|
||||
utarray_inserta(dst, src, utarray_len(dst)); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_erase(a,pos,len) do { \
|
||||
if ((a)->icd.dtor) { \
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (len); _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a, (pos) + _ut_i)); \
|
||||
} \
|
||||
} \
|
||||
if ((a)->i > ((pos) + (len))) { \
|
||||
memmove(_utarray_eltptr(a, pos), _utarray_eltptr(a, (pos) + (len)), \
|
||||
((a)->i - ((pos) + (len))) * (a)->icd.sz); \
|
||||
} \
|
||||
(a)->i -= (len); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_renew(a,u) do { \
|
||||
if (a) utarray_clear(a); \
|
||||
else utarray_new(a, u); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_clear(a) do { \
|
||||
if ((a)->i > 0) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
unsigned _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(_utarray_eltptr(a, _ut_i)); \
|
||||
} \
|
||||
} \
|
||||
(a)->i = 0; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_sort(a,cmp) do { \
|
||||
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
|
||||
|
||||
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
|
||||
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
|
||||
#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
|
||||
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
|
||||
#define utarray_eltidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1)
|
||||
|
||||
/* last we pre-define a few icd for common utarrays of ints and strings */
|
||||
static void utarray_str_cpy(void *dst, const void *src) {
|
||||
char **_src = (char**)src, **_dst = (char**)dst;
|
||||
*_dst = (*_src == NULL) ? NULL : _strdup(*_src);
|
||||
}
|
||||
static void utarray_str_dtor(void *elt) {
|
||||
char **eltc = (char**)elt;
|
||||
if (*eltc != NULL) free(*eltc);
|
||||
}
|
||||
static const UT_icd ut_str_icd UTARRAY_UNUSED = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
|
||||
static const UT_icd ut_int_icd UTARRAY_UNUSED = {sizeof(int),NULL,NULL,NULL};
|
||||
static const UT_icd ut_ptr_icd UTARRAY_UNUSED = {sizeof(void*),NULL,NULL,NULL};
|
||||
|
||||
|
||||
#endif /* UTARRAY_H */
|
||||
1107
uthash/uthash.h
Normal file
1107
uthash/uthash.h
Normal file
File diff suppressed because it is too large
Load Diff
2
uthash/uthash.url
Normal file
2
uthash/uthash.url
Normal file
@ -0,0 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://troydhanson.github.io/uthash/index.html
|
||||
1073
uthash/utlist.h
Normal file
1073
uthash/utlist.h
Normal file
File diff suppressed because it is too large
Load Diff
108
uthash/utringbuffer.h
Normal file
108
uthash/utringbuffer.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a ring-buffer implementation using macros
|
||||
*/
|
||||
#ifndef UTRINGBUFFER_H
|
||||
#define UTRINGBUFFER_H
|
||||
|
||||
#define UTRINGBUFFER_VERSION 2.0.2
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "utarray.h" // for "UT_icd"
|
||||
|
||||
typedef struct {
|
||||
unsigned i; /* index of next available slot; wraps at n */
|
||||
unsigned n; /* capacity */
|
||||
unsigned char f; /* full */
|
||||
UT_icd icd; /* initializer, copy and destructor functions */
|
||||
char *d; /* n slots of size icd->sz */
|
||||
} UT_ringbuffer;
|
||||
|
||||
#define utringbuffer_init(a, _n, _icd) do { \
|
||||
memset(a, 0, sizeof(UT_ringbuffer)); \
|
||||
(a)->icd = *(_icd); \
|
||||
(a)->n = (_n); \
|
||||
if ((a)->n) { (a)->d = (char*)malloc((a)->n * (_icd)->sz); } \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_clear(a) do { \
|
||||
if ((a)->icd.dtor) { \
|
||||
if ((a)->f) { \
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (a)->n; ++_ut_i) { \
|
||||
(a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
unsigned _ut_i; \
|
||||
for (_ut_i = 0; _ut_i < (a)->i; ++_ut_i) { \
|
||||
(a)->icd.dtor(utringbuffer_eltptr(a, _ut_i)); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
(a)->i = 0; \
|
||||
(a)->f = 0; \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_done(a) do { \
|
||||
utringbuffer_clear(a); \
|
||||
free((a)->d); (a)->d = NULL; \
|
||||
(a)->n = 0; \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_new(a,n,_icd) do { \
|
||||
a = (UT_ringbuffer*)malloc(sizeof(UT_ringbuffer)); \
|
||||
utringbuffer_init(a, n, _icd); \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_free(a) do { \
|
||||
utringbuffer_done(a); \
|
||||
free(a); \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_push_back(a,p) do { \
|
||||
if ((a)->icd.dtor && (a)->f) { (a)->icd.dtor(_utringbuffer_internalptr(a,(a)->i)); } \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utringbuffer_internalptr(a,(a)->i), p); } \
|
||||
else { memcpy(_utringbuffer_internalptr(a,(a)->i), p, (a)->icd.sz); }; \
|
||||
if (++(a)->i == (a)->n) { (a)->i = 0; (a)->f = 1; } \
|
||||
} while(0)
|
||||
|
||||
#define utringbuffer_len(a) ((a)->f ? (a)->n : (a)->i)
|
||||
#define utringbuffer_empty(a) ((a)->i == 0 && !(a)->f)
|
||||
#define utringbuffer_full(a) ((a)->f != 0)
|
||||
|
||||
#define _utringbuffer_real_idx(a,j) ((a)->f ? ((j) + (a)->i) % (a)->n : (j))
|
||||
#define _utringbuffer_internalptr(a,j) ((void*)((a)->d + ((a)->icd.sz * (j))))
|
||||
#define utringbuffer_eltptr(a,j) ((0 <= (j) && (j) < utringbuffer_len(a)) ? _utringbuffer_internalptr(a,_utringbuffer_real_idx(a,j)) : NULL)
|
||||
|
||||
#define _utringbuffer_fake_idx(a,j) ((a)->f ? ((j) + (a)->n - (a)->i) % (a)->n : (j))
|
||||
#define _utringbuffer_internalidx(a,e) (((char*)(e) >= (a)->d) ? (((char*)(e) - (a)->d)/(a)->icd.sz) : -1)
|
||||
#define utringbuffer_eltidx(a,e) _utringbuffer_fake_idx(a, _utringbuffer_internalidx(a,e))
|
||||
|
||||
#define utringbuffer_front(a) utringbuffer_eltptr(a,0)
|
||||
#define utringbuffer_next(a,e) ((e)==NULL ? utringbuffer_front(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)+1))
|
||||
#define utringbuffer_prev(a,e) ((e)==NULL ? utringbuffer_back(a) : utringbuffer_eltptr(a, utringbuffer_eltidx(a,e)-1))
|
||||
#define utringbuffer_back(a) (utringbuffer_empty(a) ? NULL : utringbuffer_eltptr(a, utringbuffer_len(a) - 1))
|
||||
|
||||
#endif /* UTRINGBUFFER_H */
|
||||
398
uthash/utstring.h
Normal file
398
uthash/utstring.h
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
Copyright (c) 2008-2017, Troy D. Hanson http://troydhanson.github.com/uthash/
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* a dynamic string implementation using macros
|
||||
*/
|
||||
#ifndef UTSTRING_H
|
||||
#define UTSTRING_H
|
||||
|
||||
#define UTSTRING_VERSION 2.0.2
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UTSTRING_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define UTSTRING_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef oom
|
||||
#define oom() exit(-1)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *d;
|
||||
size_t n; /* allocd size */
|
||||
size_t i; /* index of first unused byte */
|
||||
} UT_string;
|
||||
|
||||
#define utstring_reserve(s,amt) \
|
||||
do { \
|
||||
if (((s)->n - (s)->i) < (size_t)(amt)) { \
|
||||
char *utstring_tmp = (char*)realloc( \
|
||||
(s)->d, (s)->n + (amt)); \
|
||||
if (utstring_tmp == NULL) oom(); \
|
||||
(s)->d = utstring_tmp; \
|
||||
(s)->n += (amt); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_init(s) \
|
||||
do { \
|
||||
(s)->n = 0; (s)->i = 0; (s)->d = NULL; \
|
||||
utstring_reserve(s,100); \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_done(s) \
|
||||
do { \
|
||||
if ((s)->d != NULL) free((s)->d); \
|
||||
(s)->n = 0; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_free(s) \
|
||||
do { \
|
||||
utstring_done(s); \
|
||||
free(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_new(s) \
|
||||
do { \
|
||||
s = (UT_string*)calloc(sizeof(UT_string),1); \
|
||||
if (!s) oom(); \
|
||||
utstring_init(s); \
|
||||
} while(0)
|
||||
|
||||
#define utstring_renew(s) \
|
||||
do { \
|
||||
if (s) { \
|
||||
utstring_clear(s); \
|
||||
} else { \
|
||||
utstring_new(s); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utstring_clear(s) \
|
||||
do { \
|
||||
(s)->i = 0; \
|
||||
(s)->d[0] = '\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_bincpy(s,b,l) \
|
||||
do { \
|
||||
utstring_reserve((s),(l)+1); \
|
||||
if (l) memcpy(&(s)->d[(s)->i], b, l); \
|
||||
(s)->i += (l); \
|
||||
(s)->d[(s)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_concat(dst,src) \
|
||||
do { \
|
||||
utstring_reserve((dst),((src)->i)+1); \
|
||||
if ((src)->i) memcpy(&(dst)->d[(dst)->i], (src)->d, (src)->i); \
|
||||
(dst)->i += (src)->i; \
|
||||
(dst)->d[(dst)->i]='\0'; \
|
||||
} while(0)
|
||||
|
||||
#define utstring_len(s) ((s)->i)
|
||||
|
||||
#define utstring_body(s) ((s)->d)
|
||||
|
||||
UTSTRING_UNUSED static void utstring_printf_va(UT_string *s, const char *fmt, va_list ap) {
|
||||
int n;
|
||||
va_list cp;
|
||||
for (;;) {
|
||||
#ifdef _WIN32
|
||||
cp = ap;
|
||||
#else
|
||||
va_copy(cp, ap);
|
||||
#endif
|
||||
n = vsnprintf (&s->d[s->i], s->n-s->i, fmt, cp);
|
||||
va_end(cp);
|
||||
|
||||
if ((n > -1) && ((size_t) n < (s->n-s->i))) {
|
||||
s->i += n;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else try again with more space. */
|
||||
if (n > -1) utstring_reserve(s,n+1); /* exact */
|
||||
else utstring_reserve(s,(s->n)*2); /* 2x */
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
/* support printf format checking (2=the format string, 3=start of varargs) */
|
||||
static void utstring_printf(UT_string *s, const char *fmt, ...)
|
||||
__attribute__ (( format( printf, 2, 3) ));
|
||||
#endif
|
||||
UTSTRING_UNUSED static void utstring_printf(UT_string *s, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,fmt);
|
||||
utstring_printf_va(s,fmt,ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* begin substring search functions *
|
||||
******************************************************************************/
|
||||
/* Build KMP table from left to right. */
|
||||
UTSTRING_UNUSED static void _utstring_BuildTable(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = 0;
|
||||
j = i - 1;
|
||||
P_KMP_Table[i] = j;
|
||||
while (i < (long) P_NeedleLen)
|
||||
{
|
||||
while ( (j > -1) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i < (long) P_NeedleLen)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i] = P_KMP_Table[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Build KMP table from right to left. */
|
||||
UTSTRING_UNUSED static void _utstring_BuildTableR(
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
|
||||
i = P_NeedleLen - 1;
|
||||
j = i + 1;
|
||||
P_KMP_Table[i + 1] = j;
|
||||
while (i >= 0)
|
||||
{
|
||||
while ( (j < (long) P_NeedleLen) && (P_Needle[i] != P_Needle[j]) )
|
||||
{
|
||||
j = P_KMP_Table[j + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i >= 0)
|
||||
{
|
||||
if (P_Needle[i] == P_Needle[j])
|
||||
{
|
||||
P_KMP_Table[i + 1] = P_KMP_Table[j + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_KMP_Table[i + 1] = j;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( Multiple search mode. ) */
|
||||
UTSTRING_UNUSED static long _utstring_find(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from left to right. */
|
||||
i = j = 0;
|
||||
while ( (j < (int)P_HaystackLen) && (((P_HaystackLen - j) + i) >= P_NeedleLen) )
|
||||
{
|
||||
while ( (i > -1) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i];
|
||||
}
|
||||
i++;
|
||||
j++;
|
||||
if (i >= (int)P_NeedleLen)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j - i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( Multiple search mode. ) */
|
||||
UTSTRING_UNUSED static long _utstring_findR(
|
||||
const char *P_Haystack,
|
||||
size_t P_HaystackLen,
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen,
|
||||
long *P_KMP_Table)
|
||||
{
|
||||
long i, j;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
/* Search from right to left. */
|
||||
j = (P_HaystackLen - 1);
|
||||
i = (P_NeedleLen - 1);
|
||||
while ( (j >= 0) && (j >= i) )
|
||||
{
|
||||
while ( (i < (int)P_NeedleLen) && (P_Needle[i] != P_Haystack[j]) )
|
||||
{
|
||||
i = P_KMP_Table[i + 1];
|
||||
}
|
||||
i--;
|
||||
j--;
|
||||
if (i < 0)
|
||||
{
|
||||
/* Found. */
|
||||
V_FindPosition = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from left to right. ( One time search mode. ) */
|
||||
UTSTRING_UNUSED static long utstring_find(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = s->i - V_StartPosition;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTable(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_find(s->d + V_StartPosition,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
if (V_FindPosition >= 0)
|
||||
{
|
||||
V_FindPosition += V_StartPosition;
|
||||
}
|
||||
|
||||
free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
|
||||
|
||||
/* Search data from right to left. ( One time search mode. ) */
|
||||
UTSTRING_UNUSED static long utstring_findR(
|
||||
UT_string *s,
|
||||
long P_StartPosition, /* Start from 0. -1 means last position. */
|
||||
const char *P_Needle,
|
||||
size_t P_NeedleLen)
|
||||
{
|
||||
long V_StartPosition;
|
||||
long V_HaystackLen;
|
||||
long *V_KMP_Table;
|
||||
long V_FindPosition = -1;
|
||||
|
||||
if (P_StartPosition < 0)
|
||||
{
|
||||
V_StartPosition = s->i + P_StartPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_StartPosition = P_StartPosition;
|
||||
}
|
||||
V_HaystackLen = V_StartPosition + 1;
|
||||
if ( (V_HaystackLen >= (long) P_NeedleLen) && (P_NeedleLen > 0) )
|
||||
{
|
||||
V_KMP_Table = (long *)malloc(sizeof(long) * (P_NeedleLen + 1));
|
||||
if (V_KMP_Table != NULL)
|
||||
{
|
||||
_utstring_BuildTableR(P_Needle, P_NeedleLen, V_KMP_Table);
|
||||
|
||||
V_FindPosition = _utstring_findR(s->d,
|
||||
V_HaystackLen,
|
||||
P_Needle,
|
||||
P_NeedleLen,
|
||||
V_KMP_Table);
|
||||
|
||||
free(V_KMP_Table);
|
||||
}
|
||||
}
|
||||
|
||||
return V_FindPosition;
|
||||
}
|
||||
/*******************************************************************************
|
||||
* end substring search functions *
|
||||
******************************************************************************/
|
||||
|
||||
#endif /* UTSTRING_H */
|
||||
Loading…
Reference in New Issue
Block a user