33 Commits

Author SHA1 Message Date
d3dac752cc Indent with tabs, as is standard for this file. 2025-12-08 13:31:05 -05:00
0893be1cea Use BTreeMap instead of HashMap for notification subscriptions.
This allows us to initialize the global NotificationCenter singleton in a const
context, which eliminates the need for OnceLock.
2025-12-08 13:24:44 -05:00
d8057575ce Use a helper method for adding notification listeners. 2025-12-08 13:14:12 -05:00
d8912c58e6 Fix typo in comment. 2025-12-08 13:06:58 -05:00
b7f765e3f6 Rewrite WINGs/notification.c in Rust. 2025-12-08 13:06:04 -05:00
d88d626fbe Remove direct creation and posting of notifications from WINGs.
We can reduce the WMNotification API surface area further by getting rid of
WMCreateNotification and WMPostNotification. WMNotification remains a
first-class object, but it is no longer possible for client code to create a
notification object directly. Notifications must now be posted through
WMPostNotificationName, which handles notification creation and destruction on
its own.

This will simplify the notification lifecycle and make the Rust rewrite
simpler. (Notifications no longer need to be reference-counted, heap-allocated
objects that might be saved somewhere after they are dispatched.)

WTextField code which reused the WMNotification struct has been modified to take
parameters of the correct type directly, instead of through a WMNotification's
void* data field.
2025-12-08 13:05:20 -05:00
5847e9d68f Ditch the notification function WMRemoveNotificationObserverWithName.
This reduces the notification API in a way that is helpful for rewriting in
Rust. This function is only used in one place, and the object that is being
deregistered is free'd immediately after WMRemoveNotificationObserverWithName is
called, so it should be safe just to use WMRemoveNotificationObserver (since I
hope it's an error to keep a notification to a free'd object registered).
2025-12-08 13:05:20 -05:00
adb967ab15 Drop dead notification queue code.
This appears to have been used by now-defunct support for network
connections (WMConnection). No live code instantiates a notification queue or
pushes/dequeues notifications from a notification queue. (The global
NotificationCenter in WINGs/notification.c is still in use, so it is not going
anywhere in this commit.)
2025-12-08 13:05:20 -05:00
0c4d78a53d Drop unused macro (dead code) that invokes WMCreateNotification. 2025-12-08 13:05:20 -05:00
dcd45f0677 Make some unused public WMNotification APIs private.
`WMRetainNotification`, `WMGetDefaultNotificationQueue`,
`WMDequeueNotificationMatching`, `WMEnqueueNotification`, and
`WMEnqueueCoalesceNotification`, are only used in WINGs/notification.c. To
reduce the API surface area that needs to be migrated to Rust, they are being
made private.
2025-12-08 13:05:20 -05:00
0097d1819e Move functions on Bag which were only called by FFI code inline. 2025-12-08 13:00:14 -05:00
8270124869 Nix dead code that was left commented out. 2025-12-08 13:00:14 -05:00
89183f3bcb Rewrite WMBag in Rust.
We should eventually get rid of this entirely, in favor of something along the
lines of a sorted Vec that is fully typed (so the payload isn't just a void*).
2025-12-08 13:00:14 -05:00
46e540b1b1 Prune the WMBag API in preparation for rewriting it in Rust. 2025-12-08 13:00:14 -05:00
9802b684ae Rewrite WINGs/tree.c in Rust.
This is a bit of a red herring, since WMTree is only used in wmmenugen, which I
don't think I've ever directly used. See notes at the top of tree.rs for more
musings on whether this should be in wutil-rs at all.
2025-12-08 12:48:37 -05:00
0a04a4c12e Remove depthFirst parameter from WMTreeWalk.
WMTreeWalk is only called once, with depthFirst set to true, so we might as well
just hard-code that behavior.

Also, this parameter appears to have been misnamed (since the search is always DFS)
and should properly be named to indicate that it controls if this is a pre- or
post-order traversal.
2025-12-08 12:47:39 -05:00
e1a263cc5b Prune unused WMTree API functions.
This is a first step towards migrating WINGs/tree.c to Rust.

Happy finding: no parent pointer are actually needed, so we don't have to use a
shared structure for node pointers!
2025-12-08 12:47:39 -05:00
c298b5f96f Avoid an unnecessary allocation in wtrimspace. 2025-12-08 12:40:33 -05:00
dfd77b11a9 Don't scan ahead unnecessarily in wstrndup. 2025-12-08 12:40:33 -05:00
927cc93e0a Add string.rs to Makefile.am for wutil-rs.
Without this, `make` won't automatically rebuild wutil-rs when string.rs
changes.
2025-12-08 12:40:33 -05:00
d2046de7ff Unit tests for wtokenjoin. 2025-12-08 12:40:33 -05:00
a7a44397a4 Rewrite all functions from WUtils string.c in Rust.
These functions should be gotten rid of as we transition to Rust, but replacing
them with minimally tested Rust code should suffice as a first step.
2025-12-08 12:40:33 -05:00
72a1f8cb9e Throw some comments around the FST table for tokenizing command line.
This is slated for replacement, but it will help to be better documented first.
2025-12-08 12:40:33 -05:00
60902b9222 Use system strlcpy/strlcat instead of packaging our own.
These functions were added to glibc 2.38, so we don't even need to check for
libbsd. There isn't a strong need to worry about supporting older systems
because use of these functions should go away as we rewrite string.c in
Rust. And, apparently, they are not held in high regard historically. That's at
least 2 reasons to be rid of them.
2025-12-08 12:40:33 -05:00
46af2c27ee Tweak start-captive-wmaker.sh to behave a little more nicely.
* Select $DISPLAY dynamically because X11 likes :0 and Wayland likes :1 and who
knows what else might like some other value.
* Kill Xephyr after wmaker exits.
* 640x480 should be big enough for anyone. (And the window shouldn't get in the
way so much.)
2025-10-28 21:30:34 -04:00
026426e6c3 Remove VoidPointer impls that were commented out in previous commit. 2025-10-25 12:41:52 -04:00
564501953f Use wfree instead of XFree in a few more places.
This fixes some crashes found in cursory smoke tests. You can now open and close
some windows without crashing immediately.
2025-10-25 01:53:23 -04:00
8c68f95291 Update calls to malloc/free, etc., to use wmalloc/wfree/...
This fixes a lot of memory bugs which arose as a result of doing something
different from the system malloc/free when allocators were rewritten in Rust.

These changes originate from a different approach to writing the allocator in
Rust:
https://git.sdf.org/vitrine/wmaker/pulls/1/files#diff-04a0fd2319b9969373b75377716e45c836d22869

There are other function calls (to XFree) that need to be fixed, but that can be
done in another commit. This one is already getting large.
2025-10-24 15:35:07 -04:00
d66eb34f16 Satisfy the dangerous_implicit_autorefs lint. 2025-10-23 16:26:47 -04:00
65726a1e6a WMHashTable ownership: it doesn't own keys or values.
The WMHashTable rewrite was prematurely merged into refactor/wutil-rs, so we're
picking up the pieces now.
2025-10-23 16:25:37 -04:00
fbd6400186 Remove stale reference to libwings_rs (which should have been deleted in a rebase). 2025-10-23 16:25:01 -04:00
4f4dcf551b Restore proplist.c, which was clobbered by mistake during a rebase.
Lessons learned: don't rebase so freely, review commits properly.
2025-10-23 15:40:50 -04:00
Dan Cross
d91275d959 memory: replace most of memory.c with Rust mem
Replace `wmalloc` et al with wrappers around the Rust allocation
library.
2025-10-14 02:55:03 +00:00
83 changed files with 1878 additions and 2514 deletions

View File

@@ -15,7 +15,7 @@ wraster = $(top_builddir)/wrlib/libwraster.la
LDADD= libWUtil.la libWINGs.la $(wraster) $(wutilrs) @INTLIBS@
libWINGs_la_LIBADD = libWUtil.la $(wraster) $(wutilrs) @XLIBS@ @XFT_LIBS@ @FCLIBS@ @LIBM@ @PANGO_LIBS@
libWUtil_la_LIBADD = @LIBBSD@ $(wutilrs)
libWUtil_la_LIBADD = $(wutilrs)
EXTRA_DIST = BUGS make-rgb Examples Extras Tests
@@ -65,7 +65,6 @@ libWINGs_la_SOURCES = \
wwindow.c
libWUtil_la_SOURCES = \
bagtree.c \
error.c \
error.h \
findfile.c \
@@ -74,10 +73,7 @@ libWUtil_la_SOURCES = \
menuparser.h \
menuparser_macros.c \
misc.c \
notification.c \
proplist.c \
string.c \
tree.c \
userdefaults.c \
userdefaults.h \
usleep.c \

View File

@@ -233,7 +233,7 @@ typedef enum {
/* text movement types */
enum {
typedef enum {
WMIllegalTextMovement,
WMReturnTextMovement,
WMEscapeTextMovement,
@@ -243,13 +243,13 @@ enum {
WMRightTextMovement,
WMUpTextMovement,
WMDownTextMovement
};
} WMTextMovementType;
/* text field special events */
enum {
typedef enum {
WMInsertTextEvent,
WMDeleteTextEvent
};
} WMTextFieldSpecialEventType;
enum {
@@ -533,14 +533,11 @@ typedef struct WMBrowserDelegate {
typedef struct WMTextFieldDelegate {
void *data;
void (*didBeginEditing)(struct WMTextFieldDelegate *self,
WMNotification *notif);
void (*didBeginEditing)(struct WMTextFieldDelegate *self, WMTextMovementType reason);
void (*didChange)(struct WMTextFieldDelegate *self,
WMNotification *notif);
void (*didChange)(struct WMTextFieldDelegate *self, WMTextFieldSpecialEventType reason);
void (*didEndEditing)(struct WMTextFieldDelegate *self,
WMNotification *notif);
void (*didEndEditing)(struct WMTextFieldDelegate *self, WMTextMovementType reason);
Bool (*shouldBeginEditing)(struct WMTextFieldDelegate *self,
WMTextField *tPtr);

View File

@@ -378,10 +378,6 @@ void W_InitNotificationCenter(void);
void W_ReleaseNotificationCenter(void);
void W_FlushASAPNotificationQueue(void);
void W_FlushIdleNotificationQueue(void);
/* ---[ selection.c ]----------------------------------------------------- */

View File

@@ -173,7 +173,7 @@ typedef struct {
typedef int WMArrayIterator;
typedef void *WMBagIterator;
typedef int WMBagIterator;
typedef void WMNotificationObserverAction(void *observerData,
@@ -271,14 +271,9 @@ char* wstrconcat(const char *str1, const char *str2);
* so always assign the returned address to avoid dangling pointers. */
char* wstrappend(char *dst, const char *src);
size_t wstrlcpy(char *, const char *, size_t);
size_t wstrlcat(char *, const char *, size_t);
void wtokensplit(char *command, char ***argv, int *argc);
char* wtokennext(char *word, char **next);
char* wtokenjoin(char **list, int count);
void wtokenfree(char **tokens, int count);
@@ -484,7 +479,7 @@ void* WMArrayPrevious(WMArray *array, WMArrayIterator *iter);
for (var = WMArrayLast(array, &(i)); (i) != WANotFound; \
var = WMArrayPrevious(array, &(i)))
/* ---[ WINGs/bagtree.c ]------------------------------------------------- */
/* ---[ wutil-rs/src/bag.rs ]------------------------------------------------- */
/*
* Tree bags use a red-black tree for storage.
@@ -499,58 +494,16 @@ void* WMArrayPrevious(WMArray *array, WMArrayIterator *iter);
* Slow for storing small numbers of elements
*/
#define WMCreateBag(size) WMCreateTreeBag()
#define WMCreateBagWithDestructor(size, d) WMCreateTreeBagWithDestructor(d)
WMBag* WMCreateTreeBag(void);
WMBag* WMCreateTreeBagWithDestructor(WMFreeDataProc *destructor);
int WMGetBagItemCount(WMBag *bag);
void WMAppendBag(WMBag *bag, WMBag *other);
void WMPutInBag(WMBag *bag, void *item);
/* insert will increment the index of elements after it by 1 */
void WMInsertInBag(WMBag *bag, int index, void *item);
/* erase will remove the element from the bag,
* but will keep the index of the other elements unchanged */
int WMEraseFromBag(WMBag *bag, int index);
/* delete and remove will remove the elements and cause the elements
* after them to decrement their indexes by 1 */
int WMDeleteFromBag(WMBag *bag, int index);
int WMRemoveFromBag(WMBag *bag, void *item);
void* WMGetFromBag(WMBag *bag, int index);
void* WMReplaceInBag(WMBag *bag, int index, void *item);
#define WMSetInBag(bag, index, item) WMReplaceInBag(bag, index, item)
/* comparer must return:
* < 0 if a < b
* > 0 if a > b
* = 0 if a = b
*/
void WMSortBag(WMBag *bag, WMCompareDataProc *comparer);
void WMSetInBag(WMBag *bag, int index, void *item);
void WMEmptyBag(WMBag *bag);
void WMFreeBag(WMBag *bag);
void WMMapBag(WMBag *bag, void (*function)(void*, void*), void *data);
int WMGetFirstInBag(WMBag *bag, void *item);
int WMCountInBag(WMBag *bag, void *item);
int WMFindInBag(WMBag *bag, WMMatchDataProc *match, void *cdata);
void* WMBagFirst(WMBag *bag, WMBagIterator *ptr);
void* WMBagLast(WMBag *bag, WMBagIterator *ptr);
@@ -562,16 +515,11 @@ void* WMBagPrevious(WMBag *bag, WMBagIterator *ptr);
void* WMBagIteratorAtIndex(WMBag *bag, int index, WMBagIterator *ptr);
int WMBagIndexForIterator(WMBag *bag, WMBagIterator ptr);
/* The following 2 macros assume that the bag doesn't change in the for loop */
#define WM_ITERATE_BAG(bag, var, i) \
for (var = WMBagFirst(bag, &(i)); (i) != NULL; \
var = WMBagNext(bag, &(i)))
/* The following macro assumes that the bag doesn't change in the for loop */
#define WM_ETARETI_BAG(bag, var, i) \
for (var = WMBagLast(bag, &(i)); (i) != NULL; \
for (var = WMBagLast(bag, &(i)); (i) >= 0; \
var = WMBagPrevious(bag, &(i)))
@@ -620,14 +568,12 @@ void WMSetDataFormat(WMData *aData, unsigned format);
unsigned WMGetDataFormat(WMData *aData);
/* Storing data */
/* ---[ WINGs/tree.c ]---------------------------------------------------- */
/* ---[ wutil-rs/src/tree.rs ]---------------------------------------------------- */
/* Generic Tree and TreeNode */
WMTreeNode* WMCreateTreeNode(void *data);
WMTreeNode* WMCreateTreeNodeWithDestructor(void *data, WMFreeDataProc *destructor);
WMTreeNode* WMInsertItemInTree(WMTreeNode *parent, int index, void *item);
#define WMAddItemToTree(parent, item) WMInsertItemInTree(parent, -1, item)
@@ -636,48 +582,23 @@ WMTreeNode* WMInsertNodeInTree(WMTreeNode *parent, int index, WMTreeNode *aNode)
#define WMAddNodeToTree(parent, aNode) WMInsertNodeInTree(parent, -1, aNode)
void WMDestroyTreeNode(WMTreeNode *aNode);
void WMDeleteLeafForTreeNode(WMTreeNode *aNode, int index);
void WMRemoveLeafForTreeNode(WMTreeNode *aNode, void *leaf);
void* WMReplaceDataForTreeNode(WMTreeNode *aNode, void *newData);
void* WMGetDataForTreeNode(WMTreeNode *aNode);
int WMGetTreeNodeDepth(WMTreeNode *aNode);
WMTreeNode* WMGetParentForTreeNode(WMTreeNode *aNode);
/* Sort only the leaves of the passed node */
void WMSortLeavesForTreeNode(WMTreeNode *aNode, WMCompareDataProc *comparer);
/* Sort all tree recursively starting from the passed node */
void WMSortTree(WMTreeNode *aNode, WMCompareDataProc *comparer);
/* Returns the first node which matches node's data with cdata by 'match' */
WMTreeNode* WMFindInTree(WMTreeNode *aTree, WMMatchDataProc *match, void *cdata);
void WMSortTree(WMTreeNode *aNode, int (*comparer)(const WMTreeNode *a, const WMTreeNode *b));
/* Returns the first node where node's data matches cdata by 'match' and node is
* at most `limit' depths down from `aTree'. */
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata, int limit);
/* Returns first tree node that has data == cdata */
#define WMGetFirstInTree(aTree, cdata) WMFindInTree(aTree, NULL, cdata)
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, int (*match)(const WMTreeNode *item, const void *cdata), void *cdata, int limit);
/* Walk every node of aNode with `walk' */
void WMTreeWalk(WMTreeNode *aNode, WMTreeWalkProc * walk, void *data, Bool DepthFirst);
void WMTreeWalk(WMTreeNode *aNode, WMTreeWalkProc * walk, void *data);
/* ---[ WINGs/data.c ]---------------------------------------------------- */
/* ---[ WINGs/notification.c ]---------------------------------------------------- */
WMNotification* WMCreateNotification(const char *name, void *object, void *clientData);
void WMReleaseNotification(WMNotification *notification);
WMNotification* WMRetainNotification(WMNotification *notification);
void* WMGetNotificationClientData(WMNotification *notification);
void* WMGetNotificationObject(WMNotification *notification);
@@ -688,33 +609,10 @@ const char* WMGetNotificationName(WMNotification *notification);
void WMAddNotificationObserver(WMNotificationObserverAction *observerAction,
void *observer, const char *name, void *object);
void WMPostNotification(WMNotification *notification);
void WMRemoveNotificationObserver(void *observer);
void WMRemoveNotificationObserverWithName(void *observer, const char *name,
void *object);
void WMPostNotificationName(const char *name, void *object, void *clientData);
WMNotificationQueue* WMGetDefaultNotificationQueue(void);
WMNotificationQueue* WMCreateNotificationQueue(void);
void WMDequeueNotificationMatching(WMNotificationQueue *queue,
WMNotification *notification,
unsigned mask);
void WMEnqueueNotification(WMNotificationQueue *queue,
WMNotification *notification,
WMPostingStyle postingStyle);
void WMEnqueueCoalesceNotification(WMNotificationQueue *queue,
WMNotification *notification,
WMPostingStyle postingStyle,
unsigned coalesceMask);
/* Property Lists handling */
/* ---[ WINGs/proplist.c ]------------------------------------------------ */

View File

@@ -1,745 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "WUtil.h"
typedef struct W_Node {
struct W_Node *parent;
struct W_Node *left;
struct W_Node *right;
int color;
void *data;
int index;
} W_Node;
typedef struct W_Bag {
W_Node *root;
W_Node *nil; /* sentinel */
int count;
void (*destructor) (void *item);
} W_Bag;
#define IS_LEFT(node) (node == node->parent->left)
#define IS_RIGHT(node) (node == node->parent->right)
static void leftRotate(W_Bag * tree, W_Node * node)
{
W_Node *node2;
node2 = node->right;
node->right = node2->left;
node2->left->parent = node;
node2->parent = node->parent;
if (node->parent == tree->nil) {
tree->root = node2;
} else {
if (IS_LEFT(node)) {
node->parent->left = node2;
} else {
node->parent->right = node2;
}
}
node2->left = node;
node->parent = node2;
}
static void rightRotate(W_Bag * tree, W_Node * node)
{
W_Node *node2;
node2 = node->left;
node->left = node2->right;
node2->right->parent = node;
node2->parent = node->parent;
if (node->parent == tree->nil) {
tree->root = node2;
} else {
if (IS_LEFT(node)) {
node->parent->left = node2;
} else {
node->parent->right = node2;
}
}
node2->right = node;
node->parent = node2;
}
static void treeInsert(W_Bag * tree, W_Node * node)
{
W_Node *y = tree->nil;
W_Node *x = tree->root;
while (x != tree->nil) {
y = x;
if (node->index <= x->index)
x = x->left;
else
x = x->right;
}
node->parent = y;
if (y == tree->nil)
tree->root = node;
else if (node->index <= y->index)
y->left = node;
else
y->right = node;
}
static void rbTreeInsert(W_Bag * tree, W_Node * node)
{
W_Node *y;
treeInsert(tree, node);
node->color = 'R';
while (node != tree->root && node->parent->color == 'R') {
if (IS_LEFT(node->parent)) {
y = node->parent->parent->right;
if (y->color == 'R') {
node->parent->color = 'B';
y->color = 'B';
node->parent->parent->color = 'R';
node = node->parent->parent;
} else {
if (IS_RIGHT(node)) {
node = node->parent;
leftRotate(tree, node);
}
node->parent->color = 'B';
node->parent->parent->color = 'R';
rightRotate(tree, node->parent->parent);
}
} else {
y = node->parent->parent->left;
if (y->color == 'R') {
node->parent->color = 'B';
y->color = 'B';
node->parent->parent->color = 'R';
node = node->parent->parent;
} else {
if (IS_LEFT(node)) {
node = node->parent;
rightRotate(tree, node);
}
node->parent->color = 'B';
node->parent->parent->color = 'R';
leftRotate(tree, node->parent->parent);
}
}
}
tree->root->color = 'B';
}
static void rbDeleteFixup(W_Bag * tree, W_Node * node)
{
W_Node *w;
while (node != tree->root && node->color == 'B') {
if (IS_LEFT(node)) {
w = node->parent->right;
if (w->color == 'R') {
w->color = 'B';
node->parent->color = 'R';
leftRotate(tree, node->parent);
w = node->parent->right;
}
if (w->left->color == 'B' && w->right->color == 'B') {
w->color = 'R';
node = node->parent;
} else {
if (w->right->color == 'B') {
w->left->color = 'B';
w->color = 'R';
rightRotate(tree, w);
w = node->parent->right;
}
w->color = node->parent->color;
node->parent->color = 'B';
w->right->color = 'B';
leftRotate(tree, node->parent);
node = tree->root;
}
} else {
w = node->parent->left;
if (w->color == 'R') {
w->color = 'B';
node->parent->color = 'R';
rightRotate(tree, node->parent);
w = node->parent->left;
}
if (w->left->color == 'B' && w->right->color == 'B') {
w->color = 'R';
node = node->parent;
} else {
if (w->left->color == 'B') {
w->right->color = 'B';
w->color = 'R';
leftRotate(tree, w);
w = node->parent->left;
}
w->color = node->parent->color;
node->parent->color = 'B';
w->left->color = 'B';
rightRotate(tree, node->parent);
node = tree->root;
}
}
}
node->color = 'B';
}
static W_Node *treeMinimum(W_Node * node, W_Node * nil)
{
while (node->left != nil)
node = node->left;
return node;
}
static W_Node *treeMaximum(W_Node * node, W_Node * nil)
{
while (node->right != nil)
node = node->right;
return node;
}
static W_Node *treeSuccessor(W_Node * node, W_Node * nil)
{
W_Node *y;
if (node->right != nil) {
return treeMinimum(node->right, nil);
}
y = node->parent;
while (y != nil && node == y->right) {
node = y;
y = y->parent;
}
return y;
}
static W_Node *treePredecessor(W_Node * node, W_Node * nil)
{
W_Node *y;
if (node->left != nil) {
return treeMaximum(node->left, nil);
}
y = node->parent;
while (y != nil && node == y->left) {
node = y;
y = y->parent;
}
return y;
}
static W_Node *rbTreeDelete(W_Bag * tree, W_Node * node)
{
W_Node *nil = tree->nil;
W_Node *x, *y;
if (node->left == nil || node->right == nil) {
y = node;
} else {
y = treeSuccessor(node, nil);
}
if (y->left != nil) {
x = y->left;
} else {
x = y->right;
}
x->parent = y->parent;
if (y->parent == nil) {
tree->root = x;
} else {
if (IS_LEFT(y)) {
y->parent->left = x;
} else {
y->parent->right = x;
}
}
if (y != node) {
node->index = y->index;
node->data = y->data;
}
if (y->color == 'B') {
rbDeleteFixup(tree, x);
}
return y;
}
static W_Node *treeSearch(W_Node * root, W_Node * nil, int index)
{
if (root == nil || root->index == index) {
return root;
}
if (index < root->index) {
return treeSearch(root->left, nil, index);
} else {
return treeSearch(root->right, nil, index);
}
}
static W_Node *treeFind(W_Node * root, W_Node * nil, void *data)
{
W_Node *tmp;
if (root == nil || root->data == data)
return root;
tmp = treeFind(root->left, nil, data);
if (tmp != nil)
return tmp;
tmp = treeFind(root->right, nil, data);
return tmp;
}
#if 0
static char buf[512];
static void printNodes(W_Node * node, W_Node * nil, int depth)
{
if (node == nil) {
return;
}
printNodes(node->left, nil, depth + 1);
memset(buf, ' ', depth * 2);
buf[depth * 2] = 0;
if (IS_LEFT(node))
printf("%s/(%2i\n", buf, node->index);
else
printf("%s\\(%2i\n", buf, node->index);
printNodes(node->right, nil, depth + 1);
}
void PrintTree(WMBag * bag)
{
W_TreeBag *tree = (W_TreeBag *) bag->data;
printNodes(tree->root, tree->nil, 0);
}
#endif
WMBag *WMCreateTreeBag(void)
{
return WMCreateTreeBagWithDestructor(NULL);
}
WMBag *WMCreateTreeBagWithDestructor(WMFreeDataProc * destructor)
{
WMBag *bag;
bag = wmalloc(sizeof(WMBag));
bag->nil = wmalloc(sizeof(W_Node));
bag->nil->left = bag->nil->right = bag->nil->parent = bag->nil;
bag->nil->index = WBNotFound;
bag->root = bag->nil;
bag->destructor = destructor;
return bag;
}
int WMGetBagItemCount(WMBag * self)
{
return self->count;
}
void WMAppendBag(WMBag * self, WMBag * bag)
{
WMBagIterator ptr;
void *data;
for (data = WMBagFirst(bag, &ptr); data != NULL; data = WMBagNext(bag, &ptr)) {
WMPutInBag(self, data);
}
}
void WMPutInBag(WMBag * self, void *item)
{
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = self->count;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
self->count++;
}
void WMInsertInBag(WMBag * self, int index, void *item)
{
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = index;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
while ((ptr = treeSuccessor(ptr, self->nil)) != self->nil) {
ptr->index++;
}
self->count++;
}
static int treeDeleteNode(WMBag * self, W_Node *ptr)
{
if (ptr != self->nil) {
W_Node *tmp;
self->count--;
tmp = treeSuccessor(ptr, self->nil);
while (tmp != self->nil) {
tmp->index--;
tmp = treeSuccessor(tmp, self->nil);
}
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
return 1;
}
return 0;
}
int WMRemoveFromBag(WMBag * self, void *item)
{
W_Node *ptr = treeFind(self->root, self->nil, item);
return treeDeleteNode(self, ptr);
}
int WMEraseFromBag(WMBag * self, int index)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
if (ptr != self->nil) {
self->count--;
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
wassertrv(self->count == 0 || self->root->index >= 0, 1);
return 1;
} else {
return 0;
}
}
int WMDeleteFromBag(WMBag * self, int index)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
return treeDeleteNode(self, ptr);
}
void *WMGetFromBag(WMBag * self, int index)
{
W_Node *node;
node = treeSearch(self->root, self->nil, index);
if (node != self->nil)
return node->data;
else
return NULL;
}
int WMGetFirstInBag(WMBag * self, void *item)
{
W_Node *node;
node = treeFind(self->root, self->nil, item);
if (node != self->nil)
return node->index;
else
return WBNotFound;
}
static int treeCount(W_Node * root, W_Node * nil, void *item)
{
int count = 0;
if (root == nil)
return 0;
if (root->data == item)
count++;
if (root->left != nil)
count += treeCount(root->left, nil, item);
if (root->right != nil)
count += treeCount(root->right, nil, item);
return count;
}
int WMCountInBag(WMBag * self, void *item)
{
return treeCount(self->root, self->nil, item);
}
void *WMReplaceInBag(WMBag * self, int index, void *item)
{
W_Node *ptr = treeSearch(self->root, self->nil, index);
void *old = NULL;
if (item == NULL) {
self->count--;
ptr = rbTreeDelete(self, ptr);
if (self->destructor)
self->destructor(ptr->data);
wfree(ptr);
} else if (ptr != self->nil) {
old = ptr->data;
ptr->data = item;
} else {
W_Node *ptr;
ptr = wmalloc(sizeof(W_Node));
ptr->data = item;
ptr->index = index;
ptr->left = self->nil;
ptr->right = self->nil;
ptr->parent = self->nil;
rbTreeInsert(self, ptr);
self->count++;
}
return old;
}
void WMSortBag(WMBag * self, WMCompareDataProc * comparer)
{
void **items;
W_Node *tmp;
int i;
if (self->count == 0)
return;
items = wmalloc(sizeof(void *) * self->count);
i = 0;
tmp = treeMinimum(self->root, self->nil);
while (tmp != self->nil) {
items[i++] = tmp->data;
tmp = treeSuccessor(tmp, self->nil);
}
qsort(&items[0], self->count, sizeof(void *), comparer);
i = 0;
tmp = treeMinimum(self->root, self->nil);
while (tmp != self->nil) {
tmp->index = i;
tmp->data = items[i++];
tmp = treeSuccessor(tmp, self->nil);
}
wfree(items);
}
static void deleteTree(WMBag * self, W_Node * node)
{
if (node == self->nil)
return;
deleteTree(self, node->left);
if (self->destructor)
self->destructor(node->data);
deleteTree(self, node->right);
wfree(node);
}
void WMEmptyBag(WMBag * self)
{
deleteTree(self, self->root);
self->root = self->nil;
self->count = 0;
}
void WMFreeBag(WMBag * self)
{
WMEmptyBag(self);
wfree(self->nil);
wfree(self);
}
static void mapTree(W_Bag * tree, W_Node * node, void (*function) (void *, void *), void *data)
{
if (node == tree->nil)
return;
mapTree(tree, node->left, function, data);
(*function) (node->data, data);
mapTree(tree, node->right, function, data);
}
void WMMapBag(WMBag * self, void (*function) (void *, void *), void *data)
{
mapTree(self, self->root, function, data);
}
static int findInTree(W_Bag * tree, W_Node * node, WMMatchDataProc * function, void *cdata)
{
int index;
if (node == tree->nil)
return WBNotFound;
index = findInTree(tree, node->left, function, cdata);
if (index != WBNotFound)
return index;
if ((*function) (node->data, cdata)) {
return node->index;
}
return findInTree(tree, node->right, function, cdata);
}
int WMFindInBag(WMBag * self, WMMatchDataProc * match, void *cdata)
{
return findInTree(self, self->root, match, cdata);
}
void *WMBagFirst(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
node = treeMinimum(self->root, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagLast(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
node = treeMaximum(self->root, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagNext(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
if (*ptr == NULL)
return NULL;
node = treeSuccessor(*ptr, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagPrevious(WMBag * self, WMBagIterator * ptr)
{
W_Node *node;
if (*ptr == NULL)
return NULL;
node = treePredecessor(*ptr, self->nil);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
void *WMBagIteratorAtIndex(WMBag * self, int index, WMBagIterator * ptr)
{
W_Node *node;
node = treeSearch(self->root, self->nil, index);
if (node == self->nil) {
*ptr = NULL;
return NULL;
} else {
*ptr = node;
return node->data;
}
}
int WMBagIndexForIterator(WMBag * bag, WMBagIterator ptr)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) bag;
return ((W_Node *) ptr)->index;
}

View File

@@ -498,7 +498,7 @@ static void registerDescriptionList(WMScreen * scr, WMView * view, WMArray * ope
for (i = 0; i < count; i++) {
text = WMGetDragOperationItemText(WMGetFromArray(operationArray, i));
wstrlcpy(textListItem, text, size);
strlcpy(textListItem, text, size);
/* to next text offset */
textListItem = &(textListItem[strlen(textListItem) + 1]);

View File

@@ -76,8 +76,8 @@ char *wfindfileinarray(WMPropList *array, const char *file)
path = wmalloc(len + flen + 2);
path = memcpy(path, p, len);
path[len] = 0;
if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
if (strlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
strlcat(path, file, len + flen + 2) >= len + flen + 2) {
wfree(path);
return NULL;
}

View File

@@ -126,7 +126,7 @@ WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback * callback, void *cda
{
TimerHandler *handler;
handler = malloc(sizeof(TimerHandler));
handler = wmalloc(sizeof(TimerHandler));
if (!handler)
return NULL;
@@ -214,7 +214,7 @@ WMHandlerID WMAddIdleHandler(WMCallback * callback, void *cdata)
{
IdleHandler *handler;
handler = malloc(sizeof(IdleHandler));
handler = wmalloc(sizeof(IdleHandler));
if (!handler)
return NULL;
@@ -274,7 +274,6 @@ Bool W_CheckIdleHandlers(void)
WMArrayIterator iter;
if (!idleHandler || WMGetArrayItemCount(idleHandler) == 0) {
W_FlushIdleNotificationQueue();
/* make sure an observer in queue didn't added an idle handler */
return (idleHandler != NULL && WMGetArrayItemCount(idleHandler) > 0);
}
@@ -292,8 +291,6 @@ Bool W_CheckIdleHandlers(void)
WMFreeArray(handlerCopy);
W_FlushIdleNotificationQueue();
/* this is not necesarrily False, because one handler can re-add itself */
return (WMGetArrayItemCount(idleHandler) > 0);
}
@@ -304,7 +301,6 @@ void W_CheckTimerHandlers(void)
struct timeval now;
if (!timerHandler) {
W_FlushASAPNotificationQueue();
return;
}
@@ -331,8 +327,6 @@ void W_CheckTimerHandlers(void)
wfree(handler);
}
}
W_FlushASAPNotificationQueue();
}
/*
@@ -384,7 +378,6 @@ Bool W_HandleInputEvents(Bool waitForInput, int inputfd)
nfds = 0;
if (!extrafd && nfds == 0) {
W_FlushASAPNotificationQueue();
return False;
}
@@ -461,8 +454,6 @@ Bool W_HandleInputEvents(Bool waitForInput, int inputfd)
wfree(fds);
W_FlushASAPNotificationQueue();
return (count > 0);
#else
#ifdef HAVE_SELECT
@@ -479,7 +470,6 @@ Bool W_HandleInputEvents(Bool waitForInput, int inputfd)
nfds = 0;
if (inputfd < 0 && nfds == 0) {
W_FlushASAPNotificationQueue();
return False;
}
@@ -556,8 +546,6 @@ Bool W_HandleInputEvents(Bool waitForInput, int inputfd)
WMFreeArray(handlerCopy);
}
W_FlushASAPNotificationQueue();
return (count > 0);
#else /* not HAVE_SELECT, not HAVE_POLL */
# error Neither select nor poll. You lose.

View File

@@ -652,7 +652,7 @@ static void mpm_get_hostname(WParserMacro *this, WMenuParser parser)
return;
}
}
wstrlcpy((char *) this->value, h, sizeof(this->value) );
strlcpy((char *) this->value, h, sizeof(this->value) );
}
/* Name of the current user */
@@ -677,7 +677,7 @@ static void mpm_get_user_name(WParserMacro *this, WMenuParser parser)
user = pw_user->pw_name;
if (user == NULL) goto error_no_username;
}
wstrlcpy((char *) this->value, user, sizeof(this->value) );
strlcpy((char *) this->value, user, sizeof(this->value) );
}
/* Number id of the user under which we are running */

View File

@@ -1,482 +0,0 @@
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "WUtil.h"
#include "WINGsP.h"
typedef struct W_Notification {
const char *name;
void *object;
void *clientData;
int refCount;
} Notification;
const char *WMGetNotificationName(WMNotification * notification)
{
return notification->name;
}
void *WMGetNotificationObject(WMNotification * notification)
{
return notification->object;
}
void *WMGetNotificationClientData(WMNotification * notification)
{
return notification->clientData;
}
WMNotification *WMCreateNotification(const char *name, void *object, void *clientData)
{
Notification *nPtr;
nPtr = wmalloc(sizeof(Notification));
nPtr->name = name;
nPtr->object = object;
nPtr->clientData = clientData;
nPtr->refCount = 1;
return nPtr;
}
void WMReleaseNotification(WMNotification * notification)
{
notification->refCount--;
if (notification->refCount < 1) {
wfree(notification);
}
}
WMNotification *WMRetainNotification(WMNotification * notification)
{
notification->refCount++;
return notification;
}
/***************** Notification Center *****************/
typedef struct NotificationObserver {
WMNotificationObserverAction *observerAction;
void *observer;
const char *name;
void *object;
struct NotificationObserver *prev; /* for tables */
struct NotificationObserver *next;
struct NotificationObserver *nextAction; /* for observerTable */
} NotificationObserver;
typedef struct W_NotificationCenter {
WMHashTable *nameTable; /* names -> observer lists */
WMHashTable *objectTable; /* object -> observer lists */
NotificationObserver *nilList; /* obervers that catch everything */
WMHashTable *observerTable; /* observer -> NotificationObserver */
} NotificationCenter;
/* default (and only) center */
static NotificationCenter *notificationCenter = NULL;
void W_InitNotificationCenter(void)
{
notificationCenter = wmalloc(sizeof(NotificationCenter));
notificationCenter->nameTable = WMCreateStringHashTable();
notificationCenter->objectTable = WMCreateIdentityHashTable();
notificationCenter->nilList = NULL;
notificationCenter->observerTable = WMCreateIdentityHashTable();
}
void W_ReleaseNotificationCenter(void)
{
if (notificationCenter) {
if (notificationCenter->nameTable)
WMFreeHashTable(notificationCenter->nameTable);
if (notificationCenter->objectTable)
WMFreeHashTable(notificationCenter->objectTable);
if (notificationCenter->observerTable)
WMFreeHashTable(notificationCenter->observerTable);
wfree(notificationCenter);
notificationCenter = NULL;
}
}
void
WMAddNotificationObserver(WMNotificationObserverAction * observerAction,
void *observer, const char *name, void *object)
{
NotificationObserver *oRec, *rec;
oRec = wmalloc(sizeof(NotificationObserver));
oRec->observerAction = observerAction;
oRec->observer = observer;
oRec->name = name;
oRec->object = object;
oRec->next = NULL;
oRec->prev = NULL;
/* put this action in the list of actions for this observer */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
if (rec) {
/* if this is not the first action for the observer */
oRec->nextAction = rec;
} else {
oRec->nextAction = NULL;
}
if (!name && !object) {
/* catch-all */
oRec->next = notificationCenter->nilList;
if (notificationCenter->nilList) {
notificationCenter->nilList->prev = oRec;
}
notificationCenter->nilList = oRec;
} else if (!name) {
/* any message coming from object */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
oRec->next = rec;
if (rec) {
rec->prev = oRec;
}
} else {
/* name && (object || !object) */
rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
oRec->next = rec;
if (rec) {
rec->prev = oRec;
}
}
}
void WMPostNotification(WMNotification * notification)
{
NotificationObserver *orec, *tmp;
WMRetainNotification(notification);
/* tell the observers that want to know about a particular message */
orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name);
while (orec) {
tmp = orec->next;
if (!orec->object || !notification->object || orec->object == notification->object) {
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
}
orec = tmp;
}
/* tell the observers that want to know about an object */
orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
while (orec) {
tmp = orec->next;
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
orec = tmp;
}
/* tell the catch all observers */
orec = notificationCenter->nilList;
while (orec) {
tmp = orec->next;
/* tell the observer */
if (orec->observerAction) {
(*orec->observerAction) (orec->observer, notification);
}
orec = tmp;
}
WMReleaseNotification(notification);
}
void WMRemoveNotificationObserver(void *observer)
{
NotificationObserver *orec, *tmp, *rec;
/* get the list of actions the observer is doing */
orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
/*
* FOREACH orec IN actionlist for observer
* DO
* remove from respective lists/tables
* free
* END
*/
while (orec) {
tmp = orec->nextAction;
if (!orec->name && !orec->object) {
/* catch-all */
if (notificationCenter->nilList == orec)
notificationCenter->nilList = orec->next;
} else if (!orec->name) {
/* any message coming from object */
rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object);
if (rec == orec) {
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
} else {
WMHashRemove(notificationCenter->objectTable, orec->object);
}
}
} else {
/* name && (object || !object) */
rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
if (rec == orec) {
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
} else {
WMHashRemove(notificationCenter->nameTable, orec->name);
}
}
}
if (orec->prev)
orec->prev->next = orec->next;
if (orec->next)
orec->next->prev = orec->prev;
wfree(orec);
orec = tmp;
}
WMHashRemove(notificationCenter->observerTable, observer);
}
void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
{
NotificationObserver *orec, *tmp, *rec;
NotificationObserver *newList = NULL;
/* get the list of actions the observer is doing */
orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
WMHashRemove(notificationCenter->observerTable, observer);
/* rebuild the list of actions for the observer */
while (orec) {
tmp = orec->nextAction;
if (orec->name == name && orec->object == object) {
if (!name && !object) {
if (notificationCenter->nilList == orec)
notificationCenter->nilList = orec->next;
} else if (!name) {
rec =
(NotificationObserver *) WMHashGet(notificationCenter->objectTable,
orec->object);
if (rec == orec) {
assert(rec->prev == NULL);
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->objectTable,
orec->object, orec->next);
} else {
WMHashRemove(notificationCenter->objectTable, orec->object);
}
}
} else {
rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
orec->name);
if (rec == orec) {
assert(rec->prev == NULL);
/* replace table entry */
if (orec->next) {
WMHashInsert(notificationCenter->nameTable,
orec->name, orec->next);
} else {
WMHashRemove(notificationCenter->nameTable, orec->name);
}
}
}
if (orec->prev)
orec->prev->next = orec->next;
if (orec->next)
orec->next->prev = orec->prev;
wfree(orec);
} else {
/* append this action in the new action list */
orec->nextAction = NULL;
if (!newList) {
newList = orec;
} else {
NotificationObserver *p;
p = newList;
while (p->nextAction) {
p = p->nextAction;
}
p->nextAction = orec;
}
}
orec = tmp;
}
/* reinsert the list to the table */
if (newList) {
WMHashInsert(notificationCenter->observerTable, observer, newList);
}
}
void WMPostNotificationName(const char *name, void *object, void *clientData)
{
WMNotification *notification;
notification = WMCreateNotification(name, object, clientData);
WMPostNotification(notification);
WMReleaseNotification(notification);
}
/**************** Notification Queues ****************/
typedef struct W_NotificationQueue {
WMArray *asapQueue;
WMArray *idleQueue;
struct W_NotificationQueue *next;
} NotificationQueue;
static WMNotificationQueue *notificationQueueList = NULL;
/* default queue */
static WMNotificationQueue *notificationQueue = NULL;
WMNotificationQueue *WMGetDefaultNotificationQueue(void)
{
if (!notificationQueue)
notificationQueue = WMCreateNotificationQueue();
return notificationQueue;
}
WMNotificationQueue *WMCreateNotificationQueue(void)
{
NotificationQueue *queue;
queue = wmalloc(sizeof(NotificationQueue));
queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
queue->next = notificationQueueList;
notificationQueueList = queue;
return queue;
}
void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle)
{
WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender);
}
#define NOTIF ((WMNotification*)cdata)
#define ITEM ((WMNotification*)item)
static int matchSenderAndName(const void *item, const void *cdata)
{
return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0);
}
static int matchSender(const void *item, const void *cdata)
{
return (NOTIF->object == ITEM->object);
}
static int matchName(const void *item, const void *cdata)
{
return (strcmp(NOTIF->name, ITEM->name) == 0);
}
#undef NOTIF
#undef ITEM
void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask)
{
WMMatchDataProc *matchFunc;
if ((mask & WNCOnName) && (mask & WNCOnSender))
matchFunc = matchSenderAndName;
else if (mask & WNCOnName)
matchFunc = matchName;
else if (mask & WNCOnSender)
matchFunc = matchSender;
else
return;
WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
}
void
WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
{
if (coalesceMask != WNCNone)
WMDequeueNotificationMatching(queue, notification, coalesceMask);
switch (postingStyle) {
case WMPostNow:
WMPostNotification(notification);
WMReleaseNotification(notification);
break;
case WMPostASAP:
WMAddToArray(queue->asapQueue, notification);
break;
case WMPostWhenIdle:
WMAddToArray(queue->idleQueue, notification);
break;
}
}
void W_FlushASAPNotificationQueue(void)
{
WMNotificationQueue *queue = notificationQueueList;
while (queue) {
while (WMGetArrayItemCount(queue->asapQueue)) {
WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
WMDeleteFromArray(queue->asapQueue, 0);
}
queue = queue->next;
}
}
void W_FlushIdleNotificationQueue(void)
{
WMNotificationQueue *queue = notificationQueueList;
while (queue) {
while (WMGetArrayItemCount(queue->idleQueue)) {
WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
WMDeleteFromArray(queue->idleQueue, 0);
}
queue = queue->next;
}
}

30
WINGs/proplist.c Normal file
View File

@@ -0,0 +1,30 @@
#include <stdarg.h>
#include "WUtil.h"
/*
* This should be written in Rust whenever va_args support improves.
*/
WMPropList *WMCreatePLArray(WMPropList * elem, ...)
{
WMPropList *plist, *nelem;
va_list ap;
plist = WMCreateEmptyPLArray();
if (!elem)
return plist;
WMAddToPLArray(plist, elem);
va_start(ap, elem);
while (1) {
nelem = va_arg(ap, WMPropList *);
if (!nelem) {
va_end(ap);
return plist;
}
WMAddToPLArray(plist, elem);
}
}

View File

@@ -1,425 +0,0 @@
/*
* Until FreeBSD gets their act together;
* http://www.mail-archive.com/freebsd-hackers@freebsd.org/msg69469.html
*/
#if defined( FREEBSD )
# undef _XOPEN_SOURCE
#endif
#include "wconfig.h"
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#ifdef HAVE_BSD_STRING_H
#include <bsd/string.h>
#endif
#include "WUtil.h"
#define PRC_ALPHA 0
#define PRC_BLANK 1
#define PRC_ESCAPE 2
#define PRC_DQUOTE 3
#define PRC_EOS 4
#define PRC_SQUOTE 5
typedef struct {
short nstate;
short output;
} DFA;
static DFA mtable[9][6] = {
{{3, 1}, {0, 0}, {4, 0}, {1, 0}, {8, 0}, {6, 0}},
{{1, 1}, {1, 1}, {2, 0}, {3, 0}, {5, 0}, {1, 1}},
{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {5, 0}, {1, 1}},
{{3, 1}, {5, 0}, {4, 0}, {1, 0}, {5, 0}, {6, 0}},
{{3, 1}, {3, 1}, {3, 1}, {3, 1}, {5, 0}, {3, 1}},
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
{{6, 1}, {6, 1}, {7, 0}, {6, 1}, {5, 0}, {3, 0}},
{{6, 1}, {6, 1}, {6, 1}, {6, 1}, {5, 0}, {6, 1}},
{{-1, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, /* final state */
};
char *wtokennext(char *word, char **next)
{
char *ptr;
char *ret, *t;
int state, ctype;
t = ret = wmalloc(strlen(word) + 1);
ptr = word;
state = 0;
while (1) {
if (*ptr == 0)
ctype = PRC_EOS;
else if (*ptr == '\\')
ctype = PRC_ESCAPE;
else if (*ptr == '"')
ctype = PRC_DQUOTE;
else if (*ptr == '\'')
ctype = PRC_SQUOTE;
else if (*ptr == ' ' || *ptr == '\t')
ctype = PRC_BLANK;
else
ctype = PRC_ALPHA;
if (mtable[state][ctype].output) {
*t = *ptr;
t++;
*t = 0;
}
state = mtable[state][ctype].nstate;
ptr++;
if (mtable[state][0].output < 0) {
break;
}
}
if (*ret == 0) {
wfree(ret);
ret = NULL;
}
if (ctype == PRC_EOS)
*next = NULL;
else
*next = ptr;
return ret;
}
/* separate a string in tokens, taking " and ' into account */
void wtokensplit(char *command, char ***argv, int *argc)
{
char *token, *line;
int count;
count = 0;
line = command;
do {
token = wtokennext(line, &line);
if (token) {
if (count == 0)
*argv = wmalloc(sizeof(**argv));
else
*argv = wrealloc(*argv, (count + 1) * sizeof(**argv));
(*argv)[count++] = token;
}
} while (token != NULL && line != NULL);
*argc = count;
}
char *wtokenjoin(char **list, int count)
{
int i, j;
char *flat_string, *wspace;
j = 0;
for (i = 0; i < count; i++) {
if (list[i] != NULL && list[i][0] != 0) {
j += strlen(list[i]);
if (strpbrk(list[i], " \t"))
j += 2;
}
}
flat_string = wmalloc(j + count + 1);
for (i = 0; i < count; i++) {
if (list[i] != NULL && list[i][0] != 0) {
if (i > 0 &&
wstrlcat(flat_string, " ", j + count + 1) >= j + count + 1)
goto error;
wspace = strpbrk(list[i], " \t");
if (wspace &&
wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
goto error;
if (wstrlcat(flat_string, list[i], j + count + 1) >= j + count + 1)
goto error;
if (wspace &&
wstrlcat(flat_string, "\"", j + count + 1) >= j + count + 1)
goto error;
}
}
return flat_string;
error:
wfree(flat_string);
return NULL;
}
void wtokenfree(char **tokens, int count)
{
while (count--)
wfree(tokens[count]);
wfree(tokens);
}
char *wtrimspace(const char *s)
{
const char *t;
if (s == NULL)
return NULL;
while (isspace(*s) && *s)
s++;
t = s + strlen(s) - 1;
while (t > s && isspace(*t))
t--;
return wstrndup(s, t - s + 1);
}
char *wstrdup(const char *str)
{
assert(str != NULL);
return strcpy(wmalloc(strlen(str) + 1), str);
}
char *wstrndup(const char *str, size_t len)
{
char *copy;
assert(str != NULL);
len = WMIN(len, strlen(str));
copy = strncpy(wmalloc(len + 1), str, len);
copy[len] = 0;
return copy;
}
char *wstrconcat(const char *str1, const char *str2)
{
char *str;
size_t slen, slen1;
if (!str1 && str2)
return wstrdup(str2);
else if (str1 && !str2)
return wstrdup(str1);
else if (!str1 && !str2)
return NULL;
slen1 = strlen(str1);
slen = slen1 + strlen(str2) + 1;
str = wmalloc(slen);
strcpy(str, str1);
strcpy(str + slen1, str2);
return str;
}
char *wstrappend(char *dst, const char *src)
{
size_t slen;
if (!src || *src == 0)
return dst;
else if (!dst)
return wstrdup(src);
slen = strlen(dst) + strlen(src) + 1;
dst = wrealloc(dst, slen);
strcat(dst, src);
return dst;
}
#ifdef HAVE_STRLCAT
size_t
wstrlcat(char *dst, const char *src, size_t siz)
{
return strlcat(dst, src, siz);
}
#else
/* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Appends src to string dst of size siz (unlike strncat, siz is the
* full size of dst, not space left). At most siz-1 characters
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
* If retval >= siz, truncation occurred.
*/
size_t
wstrlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end */
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return(dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return(dlen + (s - src)); /* count does not include NUL */
}
#endif /* HAVE_STRLCAT */
#ifdef HAVE_STRLCPY
size_t
wstrlcpy(char *dst, const char *src, size_t siz)
{
return strlcpy(dst, src, siz);
}
#else
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
wstrlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif /* HAVE_STRLCPY */
/* transform `s' so that the result is safe to pass to the shell as an argument.
* returns a newly allocated string.
* with very heavy inspirations from NetBSD's shquote(3).
*/
char *wshellquote(const char *s)
{
char *p, *r, *last, *ret;
size_t slen;
int needs_quoting;
if (!s)
return NULL;
needs_quoting = !*s; /* the empty string does need quoting */
/* do not quote if consists only of the following characters */
for (p = (char *)s; *p && !needs_quoting; p++) {
needs_quoting = !(isalnum(*p) || (*p == '+') || (*p == '/') ||
(*p == '.') || (*p == ',') || (*p == '-'));
}
if (!needs_quoting)
return wstrdup(s);
for (slen = 0, p = (char *)s; *p; p++) /* count space needed (worst case) */
slen += *p == '\'' ? 4 : 1; /* every single ' becomes ''\' */
slen += 2 /* leading + trailing "'" */ + 1 /* NULL */;
ret = r = wmalloc(slen);
p = (char *)s;
last = p;
if (*p != '\'') /* if string doesn't already begin with "'" */
*r++ ='\''; /* start putting it in quotes */
while (*p) {
last = p;
if (*p == '\'') { /* turn each ' into ''\' */
if (p != s) /* except if it's the first ', in which case */
*r++ = '\''; /* only escape it */
*r++ = '\\';
*r++ = '\'';
while (*++p && *p == '\'') { /* keep turning each consecutive 's into \' */
*r++ = '\\';
*r++ = '\'';
}
if (*p) /* if more input follows, terminate */
*r++ = '\''; /* what we have so far */
} else {
*r++ = *p++;
}
}
if (*last != '\'') /* if the last one isn't already a ' */
*r++ = '\''; /* terminate the whole shebang */
*r = '\0';
return ret; /* technically, we lose (but not leak) a couple of */
/* bytes (twice the number of consecutive 's in the */
/* input or so), but since these are relatively rare */
/* and short-lived strings, not sure if a trip to */
/* wstrdup+wfree worths the gain. */
}

View File

@@ -1,255 +0,0 @@
#include <string.h>
#include "WUtil.h"
typedef struct W_TreeNode {
void *data;
/*unsigned int uflags:16; */
WMArray *leaves;
int depth;
struct W_TreeNode *parent;
WMFreeDataProc *destructor;
} W_TreeNode;
static void destroyNode(void *data)
{
WMTreeNode *aNode = (WMTreeNode *) data;
if (aNode->destructor) {
(*aNode->destructor) (aNode->data);
}
if (aNode->leaves) {
WMFreeArray(aNode->leaves);
}
wfree(aNode);
}
WMTreeNode *WMCreateTreeNode(void *data)
{
return WMCreateTreeNodeWithDestructor(data, NULL);
}
WMTreeNode *WMCreateTreeNodeWithDestructor(void *data, WMFreeDataProc * destructor)
{
WMTreeNode *aNode;
aNode = (WMTreeNode *) wmalloc(sizeof(W_TreeNode));
aNode->destructor = destructor;
aNode->data = data;
aNode->parent = NULL;
aNode->depth = 0;
aNode->leaves = NULL;
/*aNode->leaves = WMCreateArrayWithDestructor(1, destroyNode); */
return aNode;
}
WMTreeNode *WMInsertItemInTree(WMTreeNode * parent, int index, void *item)
{
WMTreeNode *aNode;
wassertrv(parent != NULL, NULL);
aNode = WMCreateTreeNodeWithDestructor(item, parent->destructor);
aNode->parent = parent;
aNode->depth = parent->depth + 1;
if (!parent->leaves) {
parent->leaves = WMCreateArrayWithDestructor(1, destroyNode);
}
if (index < 0) {
WMAddToArray(parent->leaves, aNode);
} else {
WMInsertInArray(parent->leaves, index, aNode);
}
return aNode;
}
static void updateNodeDepth(WMTreeNode * aNode, int depth)
{
int i;
aNode->depth = depth;
if (aNode->leaves) {
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
updateNodeDepth(WMGetFromArray(aNode->leaves, i), depth + 1);
}
}
}
WMTreeNode *WMInsertNodeInTree(WMTreeNode * parent, int index, WMTreeNode * aNode)
{
wassertrv(parent != NULL, NULL);
wassertrv(aNode != NULL, NULL);
aNode->parent = parent;
updateNodeDepth(aNode, parent->depth + 1);
if (!parent->leaves) {
parent->leaves = WMCreateArrayWithDestructor(1, destroyNode);
}
if (index < 0) {
WMAddToArray(parent->leaves, aNode);
} else {
WMInsertInArray(parent->leaves, index, aNode);
}
return aNode;
}
void WMDestroyTreeNode(WMTreeNode * aNode)
{
wassertr(aNode != NULL);
if (aNode->parent && aNode->parent->leaves) {
WMRemoveFromArray(aNode->parent->leaves, aNode);
} else {
destroyNode(aNode);
}
}
void WMDeleteLeafForTreeNode(WMTreeNode * aNode, int index)
{
wassertr(aNode != NULL);
wassertr(aNode->leaves != NULL);
WMDeleteFromArray(aNode->leaves, index);
}
static int sameData(const void *item, const void *data)
{
return (((WMTreeNode *) item)->data == data);
}
void WMRemoveLeafForTreeNode(WMTreeNode * aNode, void *leaf)
{
int index;
wassertr(aNode != NULL);
wassertr(aNode->leaves != NULL);
index = WMFindInArray(aNode->leaves, sameData, leaf);
if (index != WANotFound) {
WMDeleteFromArray(aNode->leaves, index);
}
}
void *WMReplaceDataForTreeNode(WMTreeNode * aNode, void *newData)
{
void *old;
wassertrv(aNode != NULL, NULL);
old = aNode->data;
aNode->data = newData;
return old;
}
void *WMGetDataForTreeNode(WMTreeNode * aNode)
{
return aNode->data;
}
int WMGetTreeNodeDepth(WMTreeNode * aNode)
{
return aNode->depth;
}
WMTreeNode *WMGetParentForTreeNode(WMTreeNode * aNode)
{
return aNode->parent;
}
void WMSortLeavesForTreeNode(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
wassertr(aNode != NULL);
if (aNode->leaves) {
WMSortArray(aNode->leaves, comparer);
}
}
static void sortLeavesForNode(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
int i;
if (!aNode->leaves)
return;
WMSortArray(aNode->leaves, comparer);
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
sortLeavesForNode(WMGetFromArray(aNode->leaves, i), comparer);
}
}
void WMSortTree(WMTreeNode * aNode, WMCompareDataProc * comparer)
{
wassertr(aNode != NULL);
sortLeavesForNode(aNode, comparer);
}
static WMTreeNode *findNodeInTree(WMTreeNode * aNode, WMMatchDataProc * match, void *cdata, int limit)
{
if (match == NULL && aNode->data == cdata)
return aNode;
else if (match && (*match) (aNode->data, cdata))
return aNode;
if (aNode->leaves && limit != 0) {
WMTreeNode *leaf;
int i;
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
leaf = findNodeInTree(WMGetFromArray(aNode->leaves, i),
match, cdata, limit > 0 ? limit - 1 : limit);
if (leaf)
return leaf;
}
}
return NULL;
}
WMTreeNode *WMFindInTree(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata)
{
wassertrv(aTree != NULL, NULL);
return findNodeInTree(aTree, match, cdata, -1);
}
WMTreeNode *WMFindInTreeWithDepthLimit(WMTreeNode * aTree, WMMatchDataProc * match, void *cdata, int limit)
{
wassertrv(aTree != NULL, NULL);
wassertrv(limit >= 0, NULL);
return findNodeInTree(aTree, match, cdata, limit);
}
void WMTreeWalk(WMTreeNode * aNode, WMTreeWalkProc * walk, void *data, Bool DepthFirst)
{
int i;
WMTreeNode *leaf;
wassertr(aNode != NULL);
if (DepthFirst)
(*walk)(aNode, data);
if (aNode->leaves) {
for (i = 0; i < WMGetArrayItemCount(aNode->leaves); i++) {
leaf = (WMTreeNode *)WMGetFromArray(aNode->leaves, i);
WMTreeWalk(leaf, walk, data, DepthFirst);
}
}
if (!DepthFirst)
(*walk)(aNode, data);
}

View File

@@ -44,9 +44,6 @@ void WMInitializeApplication(const char *applicationName, int *argc, char **argv
WMApplication.argv[i] = wstrdup(argv[i]);
}
WMApplication.argv[i] = NULL;
/* initialize notification center */
W_InitNotificationCenter();
}
void WMReleaseApplication(void) {
@@ -60,7 +57,7 @@ void WMReleaseApplication(void) {
*/
w_save_defaults_changes();
W_ReleaseNotificationCenter();
W_ClearNotificationCenter();
if (WMApplication.applicationName) {
wfree(WMApplication.applicationName);
@@ -101,21 +98,21 @@ static char *checkFile(const char *path, const char *folder, const char *ext, co
slen = strlen(path) + strlen(resource) + 1 + extralen;
ret = wmalloc(slen);
if (wstrlcpy(ret, path, slen) >= slen)
if (strlcpy(ret, path, slen) >= slen)
goto error;
if (folder &&
(wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, folder, slen) >= slen))
(strlcat(ret, "/", slen) >= slen ||
strlcat(ret, folder, slen) >= slen))
goto error;
if (ext &&
(wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, ext, slen) >= slen))
(strlcat(ret, "/", slen) >= slen ||
strlcat(ret, ext, slen) >= slen))
goto error;
if (wstrlcat(ret, "/", slen) >= slen ||
wstrlcat(ret, resource, slen) >= slen)
if (strlcat(ret, "/", slen) >= slen ||
strlcat(ret, resource, slen) >= slen)
goto error;
if (access(ret, F_OK) != 0)

View File

@@ -314,7 +314,7 @@ static void removeColumn(WMBrowser * bPtr, int column)
wfree(bPtr->titles[i]);
bPtr->titles[i] = NULL;
}
WMRemoveNotificationObserverWithName(bPtr, WMListSelectionDidChangeNotification, bPtr->columns[i]);
WMRemoveNotificationObserver(bPtr->columns[i]);
WMDestroyWidget(bPtr->columns[i]);
bPtr->columns[i] = NULL;
}
@@ -720,14 +720,14 @@ char *WMGetBrowserPathToColumn(WMBrowser * bPtr, int column)
path = wmalloc(slen);
/* ignore first `/' */
for (i = 0; i <= column; i++) {
if (wstrlcat(path, bPtr->pathSeparator, slen) >= slen)
if (strlcat(path, bPtr->pathSeparator, slen) >= slen)
goto error;
item = WMGetListSelectedItem(bPtr->columns[i]);
if (!item)
break;
if (wstrlcat(path, item->text, slen) >= slen)
if (strlcat(path, item->text, slen) >= slen)
goto error;
}
@@ -782,7 +782,7 @@ WMArray *WMGetBrowserPaths(WMBrowser * bPtr)
path = wmalloc(slen);
/* ignore first `/' */
for (i = 0; i <= column; i++) {
wstrlcat(path, bPtr->pathSeparator, slen);
strlcat(path, bPtr->pathSeparator, slen);
if (i == column) {
item = lastItem;
} else {
@@ -790,7 +790,7 @@ WMArray *WMGetBrowserPaths(WMBrowser * bPtr)
}
if (!item)
break;
wstrlcat(path, item->text, slen);
strlcat(path, item->text, slen);
}
WMAddToArray(paths, path);
}
@@ -1130,25 +1130,25 @@ static char *createTruncatedString(WMFont * font, const char *text, int *textLen
if (width >= 3 * dLen) {
int tmpTextLen = *textLen;
if (wstrlcpy(textBuf, text, slen) >= slen)
if (strlcpy(textBuf, text, slen) >= slen)
goto error;
while (tmpTextLen && (WMWidthOfString(font, textBuf, tmpTextLen) + 3 * dLen > width))
tmpTextLen--;
if (wstrlcpy(textBuf + tmpTextLen, "...", slen) >= slen)
if (strlcpy(textBuf + tmpTextLen, "...", slen) >= slen)
goto error;
*textLen = tmpTextLen + 3;
} else if (width >= 2 * dLen) {
if (wstrlcpy(textBuf, "..", slen) >= slen)
if (strlcpy(textBuf, "..", slen) >= slen)
goto error;
*textLen = 2;
} else if (width >= dLen) {
if (wstrlcpy(textBuf, ".", slen) >= slen)
if (strlcpy(textBuf, ".", slen) >= slen)
goto error;
*textLen = 1;

View File

@@ -513,12 +513,12 @@ static void listDirectoryOnColumn(WMFilePanel * panel, int column, const char *p
if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
continue;
if (wstrlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
if (strlcpy(pbuf, path, sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (strcmp(path, "/") != 0 &&
wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
strlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
if (strlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf))
goto out;
if (stat(pbuf, &stat_buf) != 0) {
@@ -626,11 +626,11 @@ static void createDir(WMWidget *widget, void *p_panel)
file = wmalloc(slen);
if (directory &&
(wstrlcat(file, directory, slen) >= slen ||
wstrlcat(file, "/", slen) >= slen))
(strlcat(file, directory, slen) >= slen ||
strlcat(file, "/", slen) >= slen))
goto out;
if (wstrlcat(file, dirName, slen) >= slen)
if (strlcat(file, dirName, slen) >= slen)
goto out;
if (mkdir(file, 00777) != 0) {

View File

@@ -558,7 +558,7 @@ static void listFamilies(WMScreen * scr, WMFontPanel * panel)
WMListItem *item;
WM_ITERATE_ARRAY(array, fam, i) {
wstrlcpy(buffer, fam->name, sizeof(buffer));
strlcpy(buffer, fam->name, sizeof(buffer));
item = WMAddListItem(panel->famLs, buffer);
item->clientData = fam;
@@ -640,7 +640,7 @@ static void familyClick(WMWidget * w, void *data)
int top = 0;
WMListItem *fitem;
wstrlcpy(buffer, face->typeface, sizeof(buffer));
strlcpy(buffer, face->typeface, sizeof(buffer));
if (strcasecmp(face->typeface, "Roman") == 0)
top = 1;
if (strcasecmp(face->typeface, "Regular") == 0)
@@ -773,7 +773,7 @@ static void setFontPanelFontName(FontPanel * panel, const char *family, const ch
int top = 0;
WMListItem *fitem;
wstrlcpy(buffer, face->typeface, sizeof(buffer));
strlcpy(buffer, face->typeface, sizeof(buffer));
if (strcasecmp(face->typeface, "Roman") == 0)
top = 1;
if (top)

View File

@@ -610,10 +610,9 @@ WMScreen *WMCreateScreenWithRContext(Display * display, int screen, RContext * c
assert(W_ApplicationInitialized());
}
scrPtr = malloc(sizeof(W_Screen));
scrPtr = wmalloc(sizeof(W_Screen));
if (!scrPtr)
return NULL;
memset(scrPtr, 0, sizeof(W_Screen));
scrPtr->aflags.hasAppIcon = 1;

View File

@@ -166,16 +166,6 @@ typedef struct W_Text {
WMArray *xdndDestinationTypes;
} Text;
/* not used */
#if 0
#define NOTIFY(T,C,N,A) {\
WMNotification *notif = WMCreateNotification(N,T,A);\
if ((T)->delegate && (T)->delegate->C)\
(*(T)->delegate->C)((T)->delegate,notif);\
WMPostNotification(notif);\
WMReleaseNotification(notif);}
#endif
#define TYPETEXT 0
#if 0

View File

@@ -68,12 +68,6 @@ typedef struct W_TextField {
} flags;
} TextField;
#define NOTIFY(T,C,N,A) { WMNotification *notif = WMCreateNotification(N,T,A);\
if ((T)->delegate && (T)->delegate->C)\
(*(T)->delegate->C)((T)->delegate,notif);\
WMPostNotification(notif);\
WMReleaseNotification(notif);}
#define MIN_TEXT_BUFFER 2
#define TEXT_BUFFER_INCR 8
@@ -404,7 +398,7 @@ void WMInsertTextFieldText(WMTextField * tPtr, const char *text, int position)
if (position < 0 || position >= tPtr->textLen) {
/* append the text at the end */
wstrlcat(tPtr->text, text, tPtr->bufferSize);
strlcat(tPtr->text, text, tPtr->bufferSize);
tPtr->textLen += len;
tPtr->cursorPosition += len;
incrToFit(tPtr);
@@ -473,7 +467,7 @@ void WMSetTextFieldText(WMTextField * tPtr, const char *text)
tPtr->bufferSize = tPtr->textLen + TEXT_BUFFER_INCR;
tPtr->text = wrealloc(tPtr->text, tPtr->bufferSize);
}
wstrlcpy(tPtr->text, text, tPtr->bufferSize);
strlcpy(tPtr->text, text, tPtr->bufferSize);
}
tPtr->cursorPosition = tPtr->selection.position = tPtr->textLen;
@@ -906,7 +900,10 @@ static void handleEvents(XEvent * event, void *data)
paintTextField(tPtr);
NOTIFY(tPtr, didBeginEditing, WMTextDidBeginEditingNotification, NULL);
if (tPtr->delegate && tPtr->delegate->didBeginEditing) {
(*tPtr->delegate->didBeginEditing)(tPtr->delegate, 0);
}
WMPostNotificationName(WMTextDidBeginEditingNotification, tPtr, NULL);
tPtr->flags.notIllegalMovement = 0;
break;
@@ -921,8 +918,10 @@ static void handleEvents(XEvent * event, void *data)
paintTextField(tPtr);
if (!tPtr->flags.notIllegalMovement) {
NOTIFY(tPtr, didEndEditing, WMTextDidEndEditingNotification,
(void *)WMIllegalTextMovement);
if (tPtr->delegate && tPtr->delegate->didEndEditing) {
(*tPtr->delegate->didEndEditing)(tPtr->delegate, WMIllegalTextMovement);
}
WMPostNotificationName(WMTextDidEndEditingNotification, tPtr, (void *)WMIllegalTextMovement);
}
break;
@@ -943,7 +942,8 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
char buffer[64];
KeySym ksym;
const char *textEvent = NULL;
void *data = NULL;
WMTextMovementType movement_type;
WMTextFieldSpecialEventType special_field_event_type;
int count, refresh = 0;
int control_pressed = 0;
int cancelSelection = 1;
@@ -975,14 +975,14 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
tPtr->view->prevFocusChain);
tPtr->flags.notIllegalMovement = 1;
}
data = (void *)WMBacktabTextMovement;
movement_type = WMBacktabTextMovement;
} else {
if (tPtr->view->nextFocusChain) {
W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
tPtr->view->nextFocusChain);
tPtr->flags.notIllegalMovement = 1;
}
data = (void *)WMTabTextMovement;
movement_type = WMTabTextMovement;
}
textEvent = WMTextDidEndEditingNotification;
@@ -994,7 +994,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
case XK_Escape:
if (!modified) {
data = (void *)WMEscapeTextMovement;
movement_type = WMEscapeTextMovement;
textEvent = WMTextDidEndEditingNotification;
relay = False;
@@ -1008,7 +1008,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
/* FALLTHRU */
case XK_Return:
if (!modified) {
data = (void *)WMReturnTextMovement;
movement_type = WMReturnTextMovement;
textEvent = WMTextDidEndEditingNotification;
relay = False;
@@ -1165,7 +1165,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (!modified) {
if (tPtr->selection.count) {
WMDeleteTextFieldRange(tPtr, tPtr->selection);
data = (void *)WMDeleteTextEvent;
special_field_event_type = WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
} else if (tPtr->cursorPosition > 0) {
int i = oneUTF8CharBackward(&tPtr->text[tPtr->cursorPosition],
@@ -1174,7 +1174,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
range.position = tPtr->cursorPosition + i;
range.count = -i;
WMDeleteTextFieldRange(tPtr, range);
data = (void *)WMDeleteTextEvent;
special_field_event_type = WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
}
@@ -1197,7 +1197,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (!modified) {
if (tPtr->selection.count) {
WMDeleteTextFieldRange(tPtr, tPtr->selection);
data = (void *)WMDeleteTextEvent;
special_field_event_type = WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
} else if (tPtr->cursorPosition < tPtr->textLen) {
WMRange range;
@@ -1205,7 +1205,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
range.count = oneUTF8CharForward(&tPtr->text[tPtr->cursorPosition],
tPtr->textLen - tPtr->cursorPosition);
WMDeleteTextFieldRange(tPtr, range);
data = (void *)WMDeleteTextEvent;
special_field_event_type = WMDeleteTextEvent;
textEvent = WMTextDidChangeNotification;
}
@@ -1220,7 +1220,7 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
if (tPtr->selection.count)
WMDeleteTextFieldRange(tPtr, tPtr->selection);
WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
data = (void *)WMInsertTextEvent;
special_field_event_type = WMInsertTextEvent;
textEvent = WMTextDidChangeNotification;
relay = False;
@@ -1255,21 +1255,22 @@ static void handleTextFieldKeyPress(TextField * tPtr, XEvent * event)
/*printf("(%d,%d)\n", tPtr->selection.position, tPtr->selection.count); */
if (textEvent) {
WMNotification *notif = WMCreateNotification(textEvent, tPtr, data);
if (tPtr->delegate) {
if (textEvent == WMTextDidBeginEditingNotification && tPtr->delegate->didBeginEditing)
(*tPtr->delegate->didBeginEditing) (tPtr->delegate, notif);
(*tPtr->delegate->didBeginEditing) (tPtr->delegate, movement_type);
else if (textEvent == WMTextDidEndEditingNotification && tPtr->delegate->didEndEditing)
(*tPtr->delegate->didEndEditing) (tPtr->delegate, notif);
(*tPtr->delegate->didEndEditing) (tPtr->delegate, movement_type);
else if (textEvent == WMTextDidChangeNotification && tPtr->delegate->didChange)
(*tPtr->delegate->didChange) (tPtr->delegate, notif);
(*tPtr->delegate->didChange) (tPtr->delegate, special_field_event_type);
}
WMPostNotification(notif);
WMReleaseNotification(notif);
if (textEvent == WMTextDidBeginEditingNotification || textEvent == WMTextDidEndEditingNotification) {
WMPostNotificationName(textEvent, tPtr, (void *)movement_type);
} else if (textEvent == WMTextDidChangeNotification) {
WMPostNotificationName(textEvent, tPtr, (void *)special_field_event_type);
}
}
if (refresh)
@@ -1345,7 +1346,10 @@ static void pasteText(WMView * view, Atom selection, Atom target, Time timestamp
str = (char *)WMDataBytes(data);
WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
} else {
int n;
@@ -1355,7 +1359,10 @@ static void pasteText(WMView * view, Atom selection, Atom target, Time timestamp
str[n] = 0;
WMInsertTextFieldText(tPtr, str, tPtr->cursorPosition);
XFree(str);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification, (void *)WMInsertTextEvent);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
}
}
}
@@ -1477,8 +1484,10 @@ static void handleTextFieldActionEvents(XEvent * event, void *data)
text[n] = 0;
WMInsertTextFieldText(tPtr, text, tPtr->cursorPosition);
XFree(text);
NOTIFY(tPtr, didChange, WMTextDidChangeNotification,
(void *)WMInsertTextEvent);
if (tPtr->delegate && tPtr->delegate->didChange) {
(*tPtr->delegate->didChange)(tPtr->delegate, WMInsertTextEvent);
}
WMPostNotificationName(WMTextDidChangeNotification, tPtr, (void *)WMInsertTextEvent);
}
} else {
tPtr->flags.waitingSelection = 1;

View File

@@ -129,7 +129,7 @@ static void autoDelayChanged(void *observerData, WMNotification *notification)
}
char *value = WMGetTextFieldText(anAutoDelayT);
adjustButtonSelectionBasedOnValue(panel, row, value);
free(value);
wfree(value);
return;
}
}

View File

@@ -138,7 +138,7 @@ static void storeData(_Panel * panel)
if (sscanf(str, "%i", &i) != 1)
i = 0;
SetIntegerForKey(i, "RaiseDelay");
free(str);
wfree(str);
SetBoolForKey(WMGetButtonSelected(panel->ignB), "IgnoreFocusClick");
SetBoolForKey(WMGetButtonSelected(panel->newB), "AutoFocus");

View File

@@ -147,7 +147,7 @@ static void storeData(_Panel * panel)
if (sscanf(str, "%i", &i) != 1)
i = 0;
SetIntegerForKey(i, "HotCornerDelay");
free(str);
wfree(str);
SetIntegerForKey(WMGetSliderValue(panel->hceS), "HotCornerEdge");

View File

@@ -365,7 +365,7 @@ char *capture_shortcut(Display *dpy, Bool *capturing, Bool convert_case)
if ((numlock_mask != Mod5Mask) && (ev.xkey.state & Mod5Mask))
strcat(buffer, "Mod5+");
wstrlcat(buffer, key, sizeof(buffer));
strlcat(buffer, key, sizeof(buffer));
return wstrdup(buffer);
}

View File

@@ -67,7 +67,6 @@ WPrefs_DEPENDENCIES = $(top_builddir)/WINGs/libWINGs.la
WPrefs_LDADD = \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a\
$(top_builddir)/wings-rs/target/debug/libwings_rs.la\
$(top_builddir)/WINGs/libWINGs.la\
$(top_builddir)/WINGs/libWUtil.la\
$(top_builddir)/wrlib/libwraster.la \

View File

@@ -824,18 +824,15 @@ static void stopEditItem(WEditMenu * menu, Bool apply)
menu->flags.isEditing = 0;
}
static void textEndedEditing(struct WMTextFieldDelegate *self, WMNotification * notif)
static void textEndedEditing(struct WMTextFieldDelegate *self, WMTextMovementType reason)
{
WEditMenu *menu = (WEditMenu *) self->data;
uintptr_t reason;
int i;
WEditMenuItem *item;
if (!menu->flags.isEditing)
return;
reason = (uintptr_t)WMGetNotificationClientData(notif);
switch (reason) {
case WMEscapeTextMovement:
stopEditItem(menu, False);

View File

@@ -391,39 +391,6 @@ dnl the flag 'O_NOFOLLOW' for 'open' is used in WINGs
WM_FUNC_OPEN_NOFOLLOW
dnl Check for strlcat/strlcpy
dnl =========================
m4_divert_push([INIT_PREPARE])dnl
AC_ARG_WITH([libbsd],
[AS_HELP_STRING([--without-libbsd], [do not use libbsd for strlcat and strlcpy [default=check]])],
[AS_IF([test "x$with_libbsd" != "xno"],
[with_libbsd=bsd],
[with_libbsd=]
)],
[with_libbsd=bsd])
m4_divert_pop([INIT_PREPARE])dnl
tmp_libs=$LIBS
AC_SEARCH_LIBS([strlcat],[$with_libbsd],
[AC_DEFINE(HAVE_STRLCAT, 1, [Define if strlcat is available])],
[],
[]
)
AC_SEARCH_LIBS([strlcpy],[$with_libbsd],
[AC_DEFINE(HAVE_STRLCAT, 1, [Define if strlcpy is available])],
[],
[]
)
LIBS=$tmp_libs
LIBBSD=
AS_IF([test "x$ac_cv_search_strlcat" = "x-lbsd" -o "x$ac_cv_search_strlcpy" = "x-lbsd"],
[LIBBSD=-lbsd
AC_CHECK_HEADERS([bsd/string.h])]
)
AC_SUBST(LIBBSD)
dnl Check for OpenBSD kernel memory interface - kvm(3)
dnl ==================================================
AS_IF([test "x$WM_OSDEP" = "xbsd"],

View File

@@ -94,7 +94,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
wwarning(_("appmenu: bad menu entry \"%s\" in window %lx"), slist[*index], win);
return NULL;
}
if (wstrlcpy(title, &slist[*index][pos], sizeof(title)) >= sizeof(title)) {
if (strlcpy(title, &slist[*index][pos], sizeof(title)) >= sizeof(title)) {
wwarning(_("appmenu: menu command size exceeded in window %lx"), win);
return NULL;
}
@@ -127,7 +127,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
slist[*index], win);
return NULL;
}
wstrlcpy(title, &slist[*index][pos], sizeof(title));
strlcpy(title, &slist[*index][pos], sizeof(title));
rtext[0] = 0;
} else {
if (sscanf(slist[*index], "%i %i %i %i %s %n",
@@ -137,7 +137,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
slist[*index], win);
return NULL;
}
wstrlcpy(title, &slist[*index][pos], sizeof(title));
strlcpy(title, &slist[*index][pos], sizeof(title));
}
data = wmalloc(sizeof(WAppMenuData));
if (data == NULL) {
@@ -174,7 +174,7 @@ static WMenu *parseMenuCommand(WScreen * scr, Window win, char **slist, int coun
return NULL;
}
wstrlcpy(title, &slist[*index][pos], sizeof(title));
strlcpy(title, &slist[*index][pos], sizeof(title));
*index += 1;
submenu = parseMenuCommand(scr, win, slist, count, index);

View File

@@ -2205,7 +2205,7 @@ static int getKeybind(WScreen * scr, WDefaultEntry * entry, WMPropList * value,
return True;
}
wstrlcpy(buf, val, MAX_SHORTCUT_LENGTH);
strlcpy(buf, val, MAX_SHORTCUT_LENGTH);
b = (char *)buf;

View File

@@ -39,10 +39,6 @@
#include <time.h>
#include <sys/utsname.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <signal.h>
#ifdef __FreeBSD__
#include <sys/signal.h>
@@ -609,9 +605,9 @@ static void listPixmaps(WScreen *scr, WMList *lPtr, const char *path)
if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0)
continue;
if (wstrlcpy(pbuf, apath, sizeof(pbuf)) >= sizeof(pbuf) ||
wstrlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf) ||
wstrlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf)) {
if (strlcpy(pbuf, apath, sizeof(pbuf)) >= sizeof(pbuf) ||
strlcat(pbuf, "/", sizeof(pbuf)) >= sizeof(pbuf) ||
strlcat(pbuf, dentry->d_name, sizeof(pbuf)) >= sizeof(pbuf)) {
wwarning(_("full path for file \"%s\" in \"%s\" is longer than %d bytes, skipped"),
dentry->d_name, path, (int) (sizeof(pbuf) - 1) );
continue;
@@ -1361,7 +1357,7 @@ void wShowInfoPanel(WScreen *scr)
char *posn = getPrettyOSName();
if (posn) {
snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), posn, uts.machine);
free(posn);
wfree(posn);
}
else
snprintf(buffer, sizeof(buffer), _("Running on: %s (%s)\n"), uts.sysname, uts.machine);
@@ -1393,31 +1389,6 @@ void wShowInfoPanel(WScreen *scr)
break;
}
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO2)
{
struct mallinfo2 ma = mallinfo2();
snprintf(buffer, sizeof(buffer),
#ifdef DEBUG
_("Total memory allocated: %lu kB (in use: %lu kB, %lu free chunks)\n"),
#else
_("Total memory allocated: %lu kB (in use: %lu kB)\n"),
#endif
(ma.arena + ma.hblkhd) / 1024,
(ma.uordblks + ma.hblkhd) / 1024
#ifdef DEBUG
/*
* This information is representative of the memory
* fragmentation. In ideal case it should be 1, but
* that is never possible
*/
, ma.ordblks
#endif
);
strbuf = wstrappend(strbuf, buffer);
}
#endif
strbuf = wstrappend(strbuf, _("Image formats: "));
strl = RSupportedFileFormats();
separator = NULL;

View File

@@ -3196,7 +3196,7 @@ static pid_t execCommand(WAppIcon *btn, const char *command, WSavedState *state)
setsid();
#endif
args = malloc(sizeof(char *) * (argc + 1));
args = wmalloc(sizeof(char *) * (argc + 1));
if (!args)
exit(111);
@@ -3340,8 +3340,8 @@ void wDockTrackWindowLaunch(WDock *dock, Window window)
char *command = NULL;
if (!PropGetWMClass(window, &wm_class, &wm_instance)) {
free(wm_class);
free(wm_instance);
wfree(wm_class);
wfree(wm_instance);
return;
}
@@ -3421,10 +3421,8 @@ void wDockTrackWindowLaunch(WDock *dock, Window window)
if (command)
wfree(command);
if (wm_class)
free(wm_class);
if (wm_instance)
free(wm_instance);
wfree(wm_class);
wfree(wm_instance);
}
void wClipUpdateForWorkspaceChange(WScreen *scr, int workspace)

View File

@@ -141,7 +141,7 @@ WMagicNumber wAddDeathHandler(pid_t pid, WDeathHandler * callback, void *cdata)
{
DeathHandler *handler;
handler = malloc(sizeof(DeathHandler));
handler = wmalloc(sizeof(DeathHandler));
if (!handler)
return 0;
@@ -150,7 +150,7 @@ WMagicNumber wAddDeathHandler(pid_t pid, WDeathHandler * callback, void *cdata)
handler->client_data = cdata;
if (!deathHandlers)
deathHandlers = WMCreateArrayWithDestructor(8, free);
deathHandlers = WMCreateArrayWithDestructor(8, wfree);
WMAddToArray(deathHandlers, handler);
@@ -164,7 +164,7 @@ static void wdelete_death_handler(WMagicNumber id)
if (!handler || !deathHandlers)
return;
/* array destructor will call free(handler) */
/* array destructor will call wfree(handler) */
WMRemoveFromArray(deathHandlers, handler);
}

View File

@@ -40,7 +40,7 @@ WGeometryView *WCreateGeometryView(WMScreen * scr)
widgetClass = W_RegisterUserWidget();
}
gview = malloc(sizeof(WGeometryView));
gview = wmalloc(sizeof(WGeometryView));
if (!gview) {
return NULL;
}

View File

@@ -131,7 +131,7 @@ static void setWVisualID(int screen, int val)
/* no array at all, alloc space for screen + 1 entries
* and init with default value */
wVisualID_len = screen + 1;
wVisualID = (int *)malloc(wVisualID_len * sizeof(int));
wVisualID = (int *)wmalloc(wVisualID_len * sizeof(int));
for (i = 0; i < wVisualID_len; i++) {
wVisualID[i] = -1;
}
@@ -156,7 +156,7 @@ static void setWVisualID(int screen, int val)
*/
static int initWVisualID(const char *user_str)
{
char *mystr = strdup(user_str);
char *mystr = wstrdup(user_str);
int cur_in_pos = 0;
int cur_out_pos = 0;
int cur_screen = 0;
@@ -191,7 +191,7 @@ static int initWVisualID(const char *user_str)
cur_in_pos++;
}
free(mystr);
wfree(mystr);
if (cur_screen == 0||error_found != 0)
return 1;
@@ -383,7 +383,7 @@ Bool RelaunchWindow(WWindow *wwin)
setsid();
#endif
/* argv is not null-terminated */
char **a = (char **) malloc(argc + 1);
char **a = (char **) wmalloc(argc + 1);
if (! a) {
werror("out of memory trying to relaunch the application");
Exit(-1);

View File

@@ -54,13 +54,13 @@ int PropGetWMClass(Window window, char **wm_class, char **wm_instance)
class_hint = XAllocClassHint();
if (XGetClassHint(dpy, window, class_hint) == 0) {
*wm_class = strdup("default");
*wm_instance = strdup("default");
*wm_class = wstrdup("default");
*wm_instance = wstrdup("default");
XFree(class_hint);
return False;
}
*wm_instance = strdup(class_hint->res_name);
*wm_class = strdup(class_hint->res_class);
*wm_instance = wstrdup(class_hint->res_name);
*wm_class = wstrdup(class_hint->res_class);
XFree(class_hint->res_name);
XFree(class_hint->res_class);

View File

@@ -406,7 +406,7 @@ static Bool addShortcut(const char *file, const char *shortcutDefinition, WMenu
ptr = wmalloc(sizeof(Shortcut));
wstrlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
strlcpy(buf, shortcutDefinition, MAX_SHORTCUT_LENGTH);
b = (char *)buf;
/* get modifiers */
@@ -1243,7 +1243,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
if (dentry->d_name[0] == '.')
continue;
buffer = malloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
buffer = wmalloc(strlen(path[i]) + strlen(dentry->d_name) + 4);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[i]);
break;
@@ -1288,7 +1288,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
}
}
}
free(buffer);
wfree(buffer);
}
closedir(dir);
@@ -1315,7 +1315,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
length += 7;
if (command)
length += strlen(command) + 6;
buffer = malloc(length);
buffer = wmalloc(length);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[data->index]);
break;
@@ -1353,7 +1353,7 @@ static WMenu *readMenuDirectory(WScreen *scr, const char *title, char **path, co
if (command)
length += strlen(command);
buffer = malloc(length);
buffer = wmalloc(length);
if (!buffer) {
werror(_("out of memory while constructing directory menu %s"), path[data->index]);
break;

View File

@@ -290,9 +290,9 @@ static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
}
if (instance)
free(instance);
wfree(instance);
if (class)
free(class);
wfree(class);
if (command)
wfree(command);
@@ -383,7 +383,7 @@ static pid_t execCommand(WScreen *scr, char *command)
SetupEnvironment(scr);
args = malloc(sizeof(char *) * (argc + 1));
args = wmalloc(sizeof(char *) * (argc + 1));
if (!args)
exit(111);
for (i = 0; i < argc; i++) {

View File

@@ -109,16 +109,16 @@ void Shutdown(WShutdownMode mode)
}
}
static void restoreWindows(WMBag * bag, WMBagIterator iter)
static void restoreWindows(WMBag * bag, WMBagIterator *iter)
{
WCoreWindow *next;
WCoreWindow *core;
WWindow *wwin;
if (iter == NULL) {
core = WMBagFirst(bag, &iter);
if (*iter < 0) {
core = WMBagFirst(bag, iter);
} else {
core = WMBagNext(bag, &iter);
core = WMBagNext(bag, iter);
}
if (core == NULL)
@@ -168,7 +168,8 @@ void RestoreDesktop(WScreen * scr)
wDestroyInspectorPanels();
/* reparent windows back to the root window, keeping the stacking order */
restoreWindows(scr->stacking_list, NULL);
WMBagIterator iter = -1;
restoreWindows(scr->stacking_list, &iter);
XUngrabServer(dpy);
XSetInputFocus(dpy, PointerRoot, RevertToParent, CurrentTime);

View File

@@ -244,7 +244,7 @@ reinit:
wApplicationSetBouncing(data->wapp, 0);
WMDeleteTimerHandler(data->timer);
wApplicationDestroy(data->wapp);
free(data);
wfree(data);
}
static int bounceDirection(WAppIcon *aicon)
@@ -324,7 +324,7 @@ void wAppBounce(WApplication *wapp)
wApplicationIncrementRefcount(wapp);
wApplicationSetBouncing(wapp, 1);
AppBouncerData *data = (AppBouncerData *)malloc(sizeof(AppBouncerData));
AppBouncerData *data = (AppBouncerData *)wmalloc(sizeof(AppBouncerData));
data->wapp = wapp;
data->count = data->pow = 0;
data->dir = bounceDirection(wApplicationGetAppIcon(wapp));

View File

@@ -357,8 +357,7 @@ static void drawTitle(WSwitchPanel *panel, int idecks, const char *title)
WMSetLabelText(panel->label, ntitle);
}
if (ntitle)
free(ntitle);
wfree(ntitle);
}
static WMArray *makeWindowListArray(WScreen *scr, int include_unmapped, Bool class_only)

View File

@@ -283,10 +283,10 @@ void wWindowDestroy(WWindow *wwin)
XFree(wwin->wm_hints);
if (wwin->wm_instance)
XFree(wwin->wm_instance);
wfree(wwin->wm_instance);
if (wwin->wm_class)
XFree(wwin->wm_class);
wfree(wwin->wm_class);
if (wwin->wm_gnustep_attr)
wfree(wwin->wm_gnustep_attr);
@@ -950,10 +950,10 @@ WWindow *wManageWindow(WScreen *scr, Window window)
}
if (instance)
free(instance);
wfree(instance);
if (class)
free(class);
wfree(class);
#undef ADEQUATE
}
@@ -2602,7 +2602,7 @@ void wWindowSetShape(WWindow * wwin)
if (!rects)
goto alt_code;
urec = malloc(sizeof(XRectangle) * (count + 2));
urec = wmalloc(sizeof(XRectangle) * (count + 2));
if (!urec) {
XFree(rects);
goto alt_code;
@@ -2779,7 +2779,7 @@ WMagicNumber wWindowAddSavedState(const char *instance, const char *class,
{
WWindowState *wstate;
wstate = malloc(sizeof(WWindowState));
wstate = wmalloc(sizeof(WWindowState));
if (!wstate)
return NULL;
@@ -2841,9 +2841,9 @@ WMagicNumber wWindowGetSavedState(Window win)
if (command)
wfree(command);
if (instance)
free(instance);
wfree(instance);
if (class)
free(class);
wfree(class);
return wstate;
}

View File

@@ -797,7 +797,7 @@ void wWorkspaceMenuUpdate(WScreen * scr, WMenu * menu)
i = scr->workspace_count - (menu->entry_no - MC_WORKSPACE1);
ws = menu->entry_no - MC_WORKSPACE1;
while (i > 0) {
wstrlcpy(title, scr->workspaces[ws]->name, MAX_WORKSPACENAME_WIDTH);
strlcpy(title, scr->workspaces[ws]->name, MAX_WORKSPACENAME_WIDTH);
entry = wMenuAddCallback(menu, title, switchWSCommand, (void *)ws);
entry->flags.indicator = 1;

View File

@@ -256,7 +256,7 @@ static void wXDNDGetTypeList(Display *dpy, Window window)
return;
}
typelist = malloc((count + 1) * sizeof(Atom));
typelist = wmalloc((count + 1) * sizeof(Atom));
a = (Atom *) data;
for (i = 0; i < count; i++) {
typelist[i] = a[i];
@@ -267,7 +267,7 @@ static void wXDNDGetTypeList(Display *dpy, Window window)
}
typelist[count] = 0;
XFree(data);
free(typelist);
wfree(typelist);
}
Bool wXDNDProcessClientMessage(XClientMessageEvent *event)

View File

@@ -77,10 +77,18 @@ if [ -n "$1" -a -x "$WindowMaker$1" ] ; then
shift
fi
Xephyr -screen 1080x760 :1 &
for i in $(seq 5 10) ; do
if [ "x$DISPLAY" != "x:$i" ] ; then
xephyr_display=":$i"
break
fi
done
echo "Running Xephyr on display $xephyr_display"
Xephyr -screen 640x480 "$xephyr_display" &
xephyr_pid=$!
DISPLAY=:1 gdb \
DISPLAY="$xephyr_display" gdb \
--directory "$project_base" \
--quiet \
--args "$WindowMaker" -display :1 --for-real "$@"
--args "$WindowMaker" -display "$xephyr_display" --for-real "$@"
kill $xephyr_pid

View File

@@ -28,7 +28,8 @@ wdread_LDADD = \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a \
$(liblist)
wxcopy_LDADD = @XLFLAGS@ @XLIBS@
wxcopy_LDADD = @XLFLAGS@ @XLIBS@ \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a
wxpaste_LDADD = @XLFLAGS@ @XLIBS@
@@ -84,8 +85,8 @@ wmgenmenu_LDADD = \
wmgenmenu_SOURCES = wmgenmenu.c wmgenmenu.h
wmmenugen_LDADD = \
$(top_builddir)/WINGs/libWUtil.la \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a \
$(top_builddir)/WINGs/libWUtil.la \
@INTLIBS@
wmmenugen_SOURCES = wmmenugen.c wmmenugen.h wmmenugen_misc.c \
@@ -97,6 +98,7 @@ wmiv_CFLAGS = @PANGO_CFLAGS@ @PTHREAD_CFLAGS@
wmiv_LDADD = \
$(top_builddir)/wrlib/libwraster.la \
$(top_builddir)/WINGs/libWINGs.la \
$(top_builddir)/WINGs/libWUtil.la \
$(top_builddir)/wutil-rs/target/debug/libwutil_rs.a \
@XLFLAGS@ @XLIBS@ @GFXLIBS@ \
@PANGO_LIBS@ @PTHREAD_LIBS@ @LIBEXIF@

View File

@@ -242,7 +242,7 @@ static void makeThemePack(WMPropList * style, const char *themeName)
WMDeleteFromPLArray(value, 1);
WMInsertInPLArray(value, 1, WMCreatePLString(newPath));
free(newPath);
wfree(newPath);
} else {
findCopyFile(themeDir, WMGetFromPLString(file));
}
@@ -262,7 +262,7 @@ static void makeThemePack(WMPropList * style, const char *themeName)
WMDeleteFromPLArray(value, 1);
WMInsertInPLArray(value, 1, WMCreatePLString(newPath));
free(newPath);
wfree(newPath);
} else {
findCopyFile(themeDir, WMGetFromPLString(file));
}
@@ -277,7 +277,7 @@ static void makeThemePack(WMPropList * style, const char *themeName)
WMDeleteFromPLArray(value, 2);
WMInsertInPLArray(value, 2, WMCreatePLString(newPath));
free(newPath);
wfree(newPath);
} else {
findCopyFile(themeDir, WMGetFromPLString(file));
}

View File

@@ -202,7 +202,7 @@ int change_title(XTextProperty *prop, char *filename)
XSetWMName(dpy, win, prop);
if (prop->value)
XFree(prop->value);
free(combined_title);
wfree(combined_title);
return EXIT_SUCCESS;
}
@@ -596,8 +596,8 @@ int linked_list_add(linked_list_t *list, const void *data)
{
link_t *link;
/* calloc sets the "next" field to zero. */
link = calloc(1, sizeof(link_t));
/* wmalloc zeros the buffer it returns, so the "next" is zero. */
link = wmalloc(sizeof(link_t));
if (!link) {
fprintf(stderr, "Error: memory allocation failed\n");
return EXIT_FAILURE;
@@ -627,8 +627,8 @@ void linked_list_free(linked_list_t *list)
/* Store the next value so that we don't access freed memory. */
next = link->next;
if (link->data)
free((char *)link->data);
free(link);
wfree((char *)link->data);
wfree(link);
}
}
@@ -651,7 +651,7 @@ link_t *connect_dir(char *dirpath, linked_list_t *li)
/* maybe it's a file */
struct stat stDirInfo;
if (lstat(dirpath, &stDirInfo) == 0) {
linked_list_add(li, strdup(dirpath));
linked_list_add(li, wstrdup(dirpath));
return li->first;
} else {
return NULL;
@@ -664,11 +664,11 @@ link_t *connect_dir(char *dirpath, linked_list_t *li)
else
snprintf(path, PATH_MAX, "%s%c%s", dirpath, FILE_SEPARATOR, dir[idx]->d_name);
free(dir[idx]);
wfree(dir[idx]);
if ((lstat(path, &stDirInfo) == 0) && !S_ISDIR(stDirInfo.st_mode))
linked_list_add(li, strdup(path));
linked_list_add(li, wstrdup(path));
}
free(dir);
wfree(dir);
return li->first;
}

View File

@@ -35,8 +35,8 @@
static void addWMMenuEntryCallback(WMMenuEntry *aEntry);
static void assemblePLMenuFunc(WMTreeNode *aNode, void *data);
static int dirParseFunc(const char *filename, const struct stat *st, int tflags, struct FTW *ftw);
static int menuSortFunc(const void *left, const void *right);
static int nodeFindSubMenuByNameFunc(const void *item, const void *cdata);
static int menuSortFunc(const WMTreeNode *left, const WMTreeNode *right);
static int nodeFindSubMenuByNameFunc(const WMTreeNode *tree, const void *cdata);
static WMTreeNode *findPositionInMenu(const char *submenu);
@@ -178,7 +178,7 @@ int main(int argc, char **argv)
}
WMSortTree(menu, menuSortFunc);
WMTreeWalk(menu, assemblePLMenuFunc, previousDepth, True);
WMTreeWalk(menu, assemblePLMenuFunc, previousDepth);
i = WMGetArrayItemCount(plMenuNodes);
if (i > 2) { /* more than one submenu unprocessed is almost certainly an error */
@@ -324,13 +324,13 @@ static void assemblePLMenuFunc(WMTreeNode *aNode, void *data)
/* sort the menu tree; callback for WMSortTree()
*/
static int menuSortFunc(const void *left, const void *right)
static int menuSortFunc(const WMTreeNode *left, const WMTreeNode *right)
{
WMMenuEntry *leftwm;
WMMenuEntry *rightwm;
leftwm = (WMMenuEntry *)WMGetDataForTreeNode(*(WMTreeNode **)left);
rightwm = (WMMenuEntry *)WMGetDataForTreeNode(*(WMTreeNode **)right);
leftwm = (WMMenuEntry *)WMGetDataForTreeNode(left);
rightwm = (WMMenuEntry *)WMGetDataForTreeNode(right);
/* submenus first */
if (!leftwm->CmdLine && rightwm->CmdLine)
@@ -380,11 +380,11 @@ static WMTreeNode *findPositionInMenu(const char *submenu)
/* find node where Name = cdata and node is a submenu
*/
static int nodeFindSubMenuByNameFunc(const void *item, const void *cdata)
static int nodeFindSubMenuByNameFunc(const WMTreeNode *tree, const void *cdata)
{
WMMenuEntry *wm;
wm = (WMMenuEntry *)item;
wm = (WMMenuEntry *)WMGetDataForTreeNode(tree);
if (wm->CmdLine) /* if it has a cmdline, it can't be a submenu */
return 0;

View File

@@ -121,7 +121,7 @@ void parse_locale(const char *what, char **language, char **country, char **enco
*language = wstrdup(e);
out:
free(e);
wfree(e);
return;
}

View File

@@ -398,7 +398,7 @@ static BackgroundTexture *parseTexture(RContext * rc, char *text)
RGradientStyle gtype;
int iwidth, iheight;
colors = malloc(sizeof(RColor *) * (count - 1));
colors = wmalloc(sizeof(RColor *) * (count - 1));
if (!colors) {
wwarning("out of memory while parsing texture");
goto error;
@@ -425,7 +425,7 @@ static BackgroundTexture *parseTexture(RContext * rc, char *text)
wfree(colors);
goto error;
}
if (!(colors[i - 2] = malloc(sizeof(RColor)))) {
if (!(colors[i - 2] = wmalloc(sizeof(RColor)))) {
wwarning("out of memory while parsing texture");
for (j = 0; colors[j] != NULL; j++)

View File

@@ -26,6 +26,8 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <WINGs/WUtil.h>
#include "../src/wconfig.h"
#define LINESIZE (4*1024)
@@ -197,7 +199,7 @@ int main(int argc, char **argv)
break;
}
if (buf_len == 0) {
nbuf = malloc(buf_len = l + nl + 1);
nbuf = wmalloc(buf_len = l + nl + 1);
} else if (buf_len < l + nl + 1) {
/*
* To avoid terrible performance on big input buffers,
@@ -205,12 +207,7 @@ int main(int argc, char **argv)
* current line.
*/
buf_len = 2 * buf_len + nl + 1;
/* some realloc implementations don't do malloc if buf==NULL */
if (buf == NULL) {
nbuf = malloc(buf_len);
} else {
nbuf = realloc(buf, buf_len);
}
nbuf = wrealloc(buf, buf_len);
} else {
nbuf = buf;
}

View File

@@ -6,7 +6,8 @@ lib_LTLIBRARIES = libWMaker.la
include_HEADERS = WMaker.h
AM_CPPFLAGS = $(DFLAGS) @XCFLAGS@
AM_CPPFLAGS = $(DFLAGS) @XCFLAGS@ \
-I$(top_srcdir)/WINGs -I$(top_builddir)/WINGs
libWMaker_la_LIBADD = @XLFLAGS@ @XLIBS@

View File

@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
#include <WINGs/WUtil.h>
#include "WMaker.h"
#include "app.h"
@@ -31,7 +33,7 @@ WMAppContext *WMAppCreateWithMain(Display * display, int screen_number, Window m
{
wmAppContext *ctx;
ctx = malloc(sizeof(wmAppContext));
ctx = wmalloc(sizeof(wmAppContext));
if (!ctx)
return NULL;
@@ -39,9 +41,9 @@ WMAppContext *WMAppCreateWithMain(Display * display, int screen_number, Window m
ctx->screen_number = screen_number;
ctx->our_leader_hint = False;
ctx->main_window = main_window;
ctx->windows = malloc(sizeof(Window));
ctx->windows = wmalloc(sizeof(Window));
if (!ctx->windows) {
free(ctx);
wfree(ctx);
return NULL;
}
ctx->win_count = 1;
@@ -58,13 +60,13 @@ int WMAppAddWindow(WMAppContext * app, Window window)
{
Window *win;
win = malloc(sizeof(Window) * (app->win_count + 1));
win = wmalloc(sizeof(Window) * (app->win_count + 1));
if (!win)
return False;
memcpy(win, app->windows, sizeof(Window) * app->win_count);
free(app->windows);
wfree(app->windows);
win[app->win_count] = window;
app->windows = win;

View File

@@ -26,6 +26,8 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <WINGs/WUtil.h>
#include "WMaker.h"
#include "app.h"
#include "menu.h"
@@ -37,7 +39,7 @@ WMMenu *WMMenuCreate(WMAppContext * app, char *title)
if (strlen(title) > 255)
return NULL;
menu = malloc(sizeof(wmMenu));
menu = wmalloc(sizeof(wmMenu));
if (!menu)
return NULL;
@@ -50,12 +52,12 @@ WMMenu *WMMenuCreate(WMAppContext * app, char *title)
menu->realized = False;
menu->code = app->last_menu_tag++;
menu->entryline = malloc(strlen(title) + 32);
menu->entryline2 = malloc(32);
menu->entryline = wmalloc(strlen(title) + 32);
menu->entryline2 = wmalloc(32);
if (!menu->entryline || !menu->entryline2) {
if (menu->entryline)
free(menu->entryline);
free(menu);
wfree(menu->entryline);
wfree(menu);
return NULL;
}
sprintf(menu->entryline, "%i %i %s", wmBeginMenu, menu->code, title);
@@ -77,13 +79,13 @@ WMMenuAddItem(WMMenu * menu, char *text, WMMenuAction action,
if (strlen(text) > 255)
return -1;
entry = malloc(sizeof(wmMenuEntry));
entry = wmalloc(sizeof(wmMenuEntry));
if (!entry)
return -1;
entry->entryline = malloc(strlen(text) + 100);
entry->entryline = wmalloc(strlen(text) + 100);
if (!entry->entryline) {
free(entry);
wfree(entry);
return -1;
}
@@ -125,13 +127,13 @@ int WMMenuAddSubmenu(WMMenu * menu, char *text, WMMenu * submenu)
if (strlen(text) > 255)
return -1;
entry = malloc(sizeof(wmMenuEntry));
entry = wmalloc(sizeof(wmMenuEntry));
if (!entry)
return -1;
entry->entryline = malloc(strlen(text) + 100);
entry->entryline = wmalloc(strlen(text) + 100);
if (!entry->entryline) {
free(entry);
wfree(entry);
return -1;
}
@@ -217,7 +219,7 @@ int WMRealizeMenus(WMAppContext * app)
return True;
count++;
slist = malloc(count * sizeof(char *));
slist = wmalloc(count * sizeof(char *));
if (!slist) {
return False;
}
@@ -227,10 +229,10 @@ int WMRealizeMenus(WMAppContext * app)
addItems(slist, &i, app->main_menu);
if (!XStringListToTextProperty(slist, i, &text_prop)) {
free(slist);
wfree(slist);
return False;
}
free(slist);
wfree(slist);
XSetTextProperty(app->dpy, app->main_window, &text_prop, getatom(app->dpy));
XFree(text_prop.value);

View File

@@ -82,7 +82,8 @@ libwraster_la_SOURCES += load_magick.c
endif
AM_CFLAGS = @MAGICKFLAGS@
AM_CPPFLAGS = $(DFLAGS) @HEADER_SEARCH_PATH@
AM_CPPFLAGS = $(DFLAGS) @HEADER_SEARCH_PATH@ \
-I$(top_srcdir)/WINGs -I$(top_builddir)/WINGs
libwraster_la_LIBADD = @LIBRARY_SEARCH_PATH@ @GFXLIBS@ @MAGICKLIBS@ @XLIBS@ @LIBXMU@ -lm

View File

@@ -37,6 +37,8 @@
#include <math.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "scale.h"
#include "wr_i18n.h"
@@ -104,17 +106,17 @@ static Bool allocateStandardPseudoColor(RContext * ctx, XStandardColormap * stdc
return False;
}
ctx->colors = malloc(sizeof(XColor) * ctx->ncolors);
ctx->colors = wmalloc(sizeof(XColor) * ctx->ncolors);
if (!ctx->colors) {
RErrorCode = RERR_NOMEMORY;
return False;
}
ctx->pixels = malloc(sizeof(unsigned long) * ctx->ncolors);
ctx->pixels = wmalloc(sizeof(unsigned long) * ctx->ncolors);
if (!ctx->pixels) {
free(ctx->colors);
wfree(ctx->colors);
ctx->colors = NULL;
RErrorCode = RERR_NOMEMORY;
@@ -246,15 +248,15 @@ static Bool allocatePseudoColor(RContext *ctx)
assert(cpc >= 2 && ncolors <= (1 << ctx->depth));
colors = malloc(sizeof(XColor) * ncolors);
colors = wmalloc(sizeof(XColor) * ncolors);
if (!colors) {
RErrorCode = RERR_NOMEMORY;
return False;
}
ctx->pixels = malloc(sizeof(unsigned long) * ncolors);
ctx->pixels = wmalloc(sizeof(unsigned long) * ncolors);
if (!ctx->pixels) {
free(colors);
wfree(colors);
RErrorCode = RERR_NOMEMORY;
return False;
}
@@ -343,7 +345,7 @@ static XColor *allocateGrayScale(RContext * ctx)
ctx->attribs->render_mode = RBestMatchRendering;
}
colors = malloc(sizeof(XColor) * ncolors);
colors = wmalloc(sizeof(XColor) * ncolors);
if (!colors) {
RErrorCode = RERR_NOMEMORY;
return False;
@@ -526,7 +528,7 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
RContext *context;
XGCValues gcv;
context = malloc(sizeof(RContext));
context = wmalloc(sizeof(RContext));
if (!context) {
RErrorCode = RERR_NOMEMORY;
return NULL;
@@ -537,9 +539,9 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
context->screen_number = screen_number;
context->attribs = malloc(sizeof(RContextAttributes));
context->attribs = wmalloc(sizeof(RContextAttributes));
if (!context->attribs) {
free(context);
wfree(context);
RErrorCode = RERR_NOMEMORY;
return NULL;
}
@@ -568,7 +570,7 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
templ.visualid = context->attribs->visualid;
vinfo = XGetVisualInfo(context->dpy, VisualIDMask | VisualScreenMask, &templ, &nret);
if (!vinfo || nret == 0) {
free(context);
wfree(context);
RErrorCode = RERR_BADVISUALID;
return NULL;
}
@@ -615,13 +617,13 @@ RContext *RCreateContext(Display * dpy, int screen_number, const RContextAttribu
if (context->vclass == PseudoColor || context->vclass == StaticColor) {
if (!setupPseudoColorColormap(context)) {
free(context);
wfree(context);
return NULL;
}
} else if (context->vclass == GrayScale || context->vclass == StaticGray) {
context->colors = allocateGrayScale(context);
if (!context->colors) {
free(context);
wfree(context);
return NULL;
}
} else if (context->vclass == TrueColor) {
@@ -668,9 +670,9 @@ void RDestroyContext(RContext *context)
if ((context->attribs->flags & RC_VisualID) &&
!(context->attribs->flags & RC_DefaultVisual))
XDestroyWindow(context->dpy, context->drawable);
free(context->attribs);
wfree(context->attribs);
}
free(context);
wfree(context);
}
}

View File

@@ -33,13 +33,15 @@
#include <string.h>
#include <assert.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "convert.h"
#include "xutil.h"
#include "wr_i18n.h"
#define NFREE(n) if (n) free(n)
#define NFREE(n) wfree(n)
#define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
@@ -70,7 +72,7 @@ static void release_conversion_table(void)
RConversionTable *tmp_to_delete = tmp;
tmp = tmp->next;
free(tmp_to_delete);
wfree(tmp_to_delete);
}
conversionTable = NULL;
}
@@ -83,7 +85,7 @@ static void release_std_conversion_table(void)
RStdConversionTable *tmp_to_delete = tmp;
tmp = tmp->next;
free(tmp_to_delete);
wfree(tmp_to_delete);
}
stdConversionTable = NULL;
}
@@ -108,7 +110,7 @@ static unsigned short *computeTable(unsigned short mask)
if (tmp)
return tmp->table;
tmp = (RConversionTable *) malloc(sizeof(RConversionTable));
tmp = (RConversionTable *) wmalloc(sizeof(RConversionTable));
if (tmp == NULL)
return NULL;
@@ -135,7 +137,7 @@ static unsigned int *computeStdTable(unsigned int mult, unsigned int max)
if (tmp)
return tmp->table;
tmp = (RStdConversionTable *) malloc(sizeof(RStdConversionTable));
tmp = (RStdConversionTable *) wmalloc(sizeof(RStdConversionTable));
if (tmp == NULL)
return NULL;
@@ -372,8 +374,8 @@ static RXImage *image2TrueColor(RContext * ctx, RImage * image)
signed char *nerr;
int ch = (HAS_ALPHA(image) ? 4 : 3);
err = malloc(ch * (image->width + 2));
nerr = malloc(ch * (image->width + 2));
err = wmalloc(ch * (image->width + 2));
nerr = wmalloc(ch * (image->width + 2));
if (!err || !nerr) {
NFREE(err);
NFREE(nerr);
@@ -387,8 +389,8 @@ static RXImage *image2TrueColor(RContext * ctx, RImage * image)
convertTrueColor_generic(ximg, image, err, nerr,
rtable, gtable, btable, dr, dg, db, roffs, goffs, boffs);
free(err);
free(nerr);
wfree(err);
wfree(nerr);
}
}
@@ -540,8 +542,8 @@ static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
#ifdef WRLIB_DEBUG
fprintf(stderr, "pseudo color dithering with %d colors per channel\n", cpc);
#endif
err = malloc(4 * (image->width + 3));
nerr = malloc(4 * (image->width + 3));
err = wmalloc(4 * (image->width + 3));
nerr = wmalloc(4 * (image->width + 3));
if (!err || !nerr) {
NFREE(err);
NFREE(nerr);
@@ -555,8 +557,8 @@ static RXImage *image2PseudoColor(RContext * ctx, RImage * image)
convertPseudoColor_to_8(ximg, image, err + 4, nerr + 4,
rtable, gtable, btable, dr, dg, db, ctx->pixels, cpc);
free(err);
free(nerr);
wfree(err);
wfree(nerr);
}
return ximg;
@@ -618,8 +620,8 @@ static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
fprintf(stderr, "pseudo color dithering with %d colors per channel\n",
ctx->attribs->colors_per_channel);
#endif
err = (short *)malloc(3 * (image->width + 2) * sizeof(short));
nerr = (short *)malloc(3 * (image->width + 2) * sizeof(short));
err = (short *)wmalloc(3 * (image->width + 2) * sizeof(short));
nerr = (short *)wmalloc(3 * (image->width + 2) * sizeof(short));
if (!err || !nerr) {
NFREE(err);
NFREE(nerr);
@@ -707,8 +709,8 @@ static RXImage *image2StandardPseudoColor(RContext * ctx, RImage * image)
ofs += ximg->image->bytes_per_line - image->width;
}
free(err);
free(nerr);
wfree(err);
wfree(nerr);
}
ximg->image->data = (char *)data;
@@ -773,8 +775,8 @@ static RXImage *image2GrayScale(RContext * ctx, RImage * image)
#ifdef WRLIB_DEBUG
fprintf(stderr, "grayscale dither with %d colors per channel\n", cpc);
#endif
gerr = (short *)malloc((image->width + 2) * sizeof(short));
ngerr = (short *)malloc((image->width + 2) * sizeof(short));
gerr = (short *)wmalloc((image->width + 2) * sizeof(short));
ngerr = (short *)wmalloc((image->width + 2) * sizeof(short));
if (!gerr || !ngerr) {
NFREE(gerr);
NFREE(ngerr);
@@ -830,8 +832,8 @@ static RXImage *image2GrayScale(RContext * ctx, RImage * image)
gerr = ngerr;
ngerr = terr;
}
free(gerr);
free(ngerr);
wfree(gerr);
wfree(ngerr);
}
ximg->image->data = (char *)data;

View File

@@ -26,6 +26,8 @@
#include <string.h>
#include <X11/Xlib.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "wr_i18n.h"
@@ -46,7 +48,7 @@ int RBlurImage(RImage * image)
unsigned char *pptr = NULL, *tmpp;
int ch = image->format == RRGBAFormat ? 4 : 3;
pptr = malloc(image->width * ch);
pptr = wmalloc(image->width * ch);
if (!pptr) {
RErrorCode = RERR_NOMEMORY;
return False;
@@ -138,7 +140,7 @@ int RBlurImage(RImage * image)
}
}
free(tmpp);
wfree(tmpp);
return True;
}

View File

@@ -34,6 +34,8 @@
#include <time.h>
#include <assert.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -125,7 +127,7 @@ static void init_cache(void)
RImageCacheMaxImage = IMAGE_CACHE_MAXIMUM_MAXPIXELS;
if (RImageCacheSize > 0) {
RImageCache = malloc(sizeof(RCachedImage) * RImageCacheSize);
RImageCache = wmalloc(sizeof(RCachedImage) * RImageCacheSize);
if (RImageCache == NULL) {
fprintf(stderr, _("wrlib: out of memory for image cache\n"));
return;
@@ -142,10 +144,10 @@ void RReleaseCache(void)
for (i = 0; i < RImageCacheSize; i++) {
if (RImageCache[i].file) {
RReleaseImage(RImageCache[i].image);
free(RImageCache[i].file);
wfree(RImageCache[i].file);
}
}
free(RImageCache);
wfree(RImageCache);
RImageCache = NULL;
RImageCacheSize = -1;
}
@@ -173,7 +175,7 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
return RCloneImage(RImageCache[i].image);
} else {
free(RImageCache[i].file);
wfree(RImageCache[i].file);
RImageCache[i].file = NULL;
RReleaseImage(RImageCache[i].image);
}
@@ -254,8 +256,7 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
for (i = 0; i < RImageCacheSize; i++) {
if (!RImageCache[i].file) {
RImageCache[i].file = malloc(strlen(file) + 1);
strcpy(RImageCache[i].file, file);
RImageCache[i].file = wstrdup(file);
RImageCache[i].image = RCloneImage(image);
RImageCache[i].last_modif = st.st_mtime;
RImageCache[i].last_use = time(NULL);
@@ -271,10 +272,9 @@ RImage *RLoadImage(RContext *context, const char *file, int index)
/* if no slot available, dump least recently used one */
if (!done) {
free(RImageCache[oldest_idx].file);
wfree(RImageCache[oldest_idx].file);
RReleaseImage(RImageCache[oldest_idx].image);
RImageCache[oldest_idx].file = malloc(strlen(file) + 1);
strcpy(RImageCache[oldest_idx].file, file);
RImageCache[oldest_idx].file = wstrdup(file);
RImageCache[oldest_idx].image = RCloneImage(image);
RImageCache[oldest_idx].last_modif = st.st_mtime;
RImageCache[oldest_idx].last_use = time(NULL);

View File

@@ -28,6 +28,8 @@
#include <gif_lib.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -127,7 +129,7 @@ RImage *RLoadGIF(const char *file, int index)
}
}
buffer = malloc(width * sizeof(GifPixelType));
buffer = wmalloc(width * sizeof(GifPixelType));
if (!buffer) {
RErrorCode = RERR_NOMEMORY;
goto bye;
@@ -219,7 +221,7 @@ RImage *RLoadGIF(const char *file, int index)
did_not_get_any_errors:
if (buffer)
free(buffer);
wfree(buffer);
if (gif)
#if (USE_GIF == 5) && (GIFLIB_MINOR >= 1)

View File

@@ -35,6 +35,8 @@
#include <stdnoreturn.h>
#endif
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -119,7 +121,7 @@ static RImage *do_read_jpeg_file(struct jpeg_decompress_struct *cinfo, const cha
goto abort_and_release_resources;
}
buffer[0] = (JSAMPROW) malloc(cinfo->image_width * cinfo->num_components);
buffer[0] = (JSAMPROW) wmalloc(cinfo->image_width * cinfo->num_components);
if (!buffer[0]) {
RErrorCode = RERR_NOMEMORY;
goto abort_and_release_resources;
@@ -167,7 +169,7 @@ static RImage *do_read_jpeg_file(struct jpeg_decompress_struct *cinfo, const cha
jpeg_destroy_decompress(cinfo);
fclose(file);
if (buffer[0])
free(buffer[0]);
wfree(buffer[0]);
return image;
}

View File

@@ -28,6 +28,8 @@
#include <png.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -165,7 +167,7 @@ RImage *RLoadPNG(RContext *context, const char *file)
image->background.blue = bkcolor->blue >> 8;
}
png_rows = calloc(height, sizeof(png_bytep));
png_rows = wmalloc(height * sizeof(png_bytep));
if (!png_rows) {
RErrorCode = RERR_NOMEMORY;
fclose(f);
@@ -174,7 +176,7 @@ RImage *RLoadPNG(RContext *context, const char *file)
return NULL;
}
for (y = 0; y < height; y++) {
png_rows[y] = malloc(png_get_rowbytes(png, pinfo));
png_rows[y] = wmalloc(png_get_rowbytes(png, pinfo));
if (!png_rows[y]) {
RErrorCode = RERR_NOMEMORY;
fclose(f);
@@ -182,8 +184,8 @@ RImage *RLoadPNG(RContext *context, const char *file)
png_destroy_read_struct(&png, &pinfo, &einfo);
while (y-- > 0)
if (png_rows[y])
free(png_rows[y]);
free(png_rows);
wfree(png_rows[y]);
wfree(png_rows);
return NULL;
}
}
@@ -214,7 +216,7 @@ RImage *RLoadPNG(RContext *context, const char *file)
}
for (y = 0; y < height; y++)
if (png_rows[y])
free(png_rows[y]);
free(png_rows);
wfree(png_rows[y]);
wfree(png_rows);
return image;
}

View File

@@ -29,6 +29,8 @@
#include <string.h>
#include <limits.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -161,7 +163,7 @@ static RImage *load_graymap(FILE *file, int w, int h, int max, int raw, const ch
if (raw == '5') {
char *buf;
buf = malloc(w + 1);
buf = wmalloc(w + 1);
if (!buf) {
RErrorCode = RERR_NOMEMORY;
RReleaseImage(image);
@@ -169,7 +171,7 @@ static RImage *load_graymap(FILE *file, int w, int h, int max, int raw, const ch
}
for (y = 0; y < h; y++) {
if (!fread(buf, w, 1, file)) {
free(buf);
wfree(buf);
RErrorCode = RERR_BADIMAGEFILE;
RReleaseImage(image);
return NULL;
@@ -181,7 +183,7 @@ static RImage *load_graymap(FILE *file, int w, int h, int max, int raw, const ch
*(ptr++) = buf[x];
}
}
free(buf);
wfree(buf);
}
}
}

View File

@@ -29,6 +29,8 @@
#include <webp/decode.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -110,7 +112,7 @@ RImage *RLoadWEBP(const char *file_name)
return NULL;
}
raw_data = (uint8_t *) malloc(raw_data_size);
raw_data = (uint8_t *) wmalloc(raw_data_size);
if (!raw_data) {
RErrorCode = RERR_NOMEMORY;
@@ -124,7 +126,7 @@ RImage *RLoadWEBP(const char *file_name)
if (r != raw_data_size) {
RErrorCode = RERR_READ;
free(raw_data);
wfree(raw_data);
return NULL;
}
@@ -133,7 +135,7 @@ RImage *RLoadWEBP(const char *file_name)
fprintf(stderr, _("wrlib: could not get features from WebP file \"%s\", %s\n"),
file_name, webp_message_from_status(status));
RErrorCode = RERR_BADIMAGEFILE;
free(raw_data);
wfree(raw_data);
return NULL;
}
@@ -141,7 +143,7 @@ RImage *RLoadWEBP(const char *file_name)
image = RCreateImage(features.width, features.height, True);
if (!image) {
RErrorCode = RERR_NOMEMORY;
free(raw_data);
wfree(raw_data);
return NULL;
}
ret = WebPDecodeRGBAInto(raw_data, raw_data_size, image->data,
@@ -151,7 +153,7 @@ RImage *RLoadWEBP(const char *file_name)
image = RCreateImage(features.width, features.height, False);
if (!image) {
RErrorCode = RERR_NOMEMORY;
free(raw_data);
wfree(raw_data);
return NULL;
}
ret = WebPDecodeRGBInto(raw_data, raw_data_size, image->data,
@@ -159,7 +161,7 @@ RImage *RLoadWEBP(const char *file_name)
features.width * 3);
}
free(raw_data);
wfree(raw_data);
if (!ret) {
fprintf(stderr, _("wrlib: failed to decode WebP from file \"%s\"\n"), file_name);

View File

@@ -29,6 +29,8 @@
#include <string.h>
#include <X11/xpm.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -59,11 +61,11 @@ static RImage *create_rimage_from_xpm(RContext *context, XpmImage xpm)
/* make color table */
for (i = 0; i < 4; i++) {
color_table[i] = malloc(xpm.ncolors * sizeof(unsigned char));
color_table[i] = wmalloc(xpm.ncolors * sizeof(unsigned char));
if (!color_table[i]) {
for (i = i - 1; i >= 0; i--) {
if (color_table[i])
free(color_table[i]);
wfree(color_table[i]);
}
RReleaseImage(image);
RErrorCode = RERR_NOMEMORY;
@@ -123,7 +125,7 @@ static RImage *create_rimage_from_xpm(RContext *context, XpmImage xpm)
*(data++) = color_table[3][*p];
}
for (i = 0; i < 4; i++)
free(color_table[i]);
wfree(color_table[i]);
return image;
}

View File

@@ -59,15 +59,15 @@ static void free_color_symbol_table(unsigned char *color_table[],
unsigned short *symbol_table)
{
if (color_table[0])
free(color_table[0]);
wfree(color_table[0]);
if (color_table[1])
free(color_table[1]);
wfree(color_table[1]);
if (color_table[2])
free(color_table[2]);
wfree(color_table[2]);
if (color_table[3])
free(color_table[3]);
wfree(color_table[3]);
if (symbol_table)
free(symbol_table);
wfree(symbol_table);
}
RImage *RGetImageFromXPMData(RContext * context, char **data)
@@ -95,11 +95,11 @@ RImage *RGetImageFromXPMData(RContext * context, char **data)
if (csize != 1 && csize != 2)
goto bad_format;
color_table[0] = malloc(ccount);
color_table[1] = malloc(ccount);
color_table[2] = malloc(ccount);
color_table[3] = malloc(ccount);
symbol_table = malloc(ccount * sizeof(unsigned short));
color_table[0] = wmalloc(ccount);
color_table[1] = wmalloc(ccount);
color_table[2] = wmalloc(ccount);
color_table[3] = wmalloc(ccount);
symbol_table = wmalloc(ccount * sizeof(unsigned short));
bsize = csize * w + 16;
@@ -283,14 +283,14 @@ RImage *RLoadXPM(RContext * context, const char *file)
if (csize != 1 && csize != 2)
goto bad_format;
color_table[0] = malloc(ccount);
color_table[1] = malloc(ccount);
color_table[2] = malloc(ccount);
color_table[3] = malloc(ccount);
symbol_table = malloc(ccount * sizeof(unsigned short));
color_table[0] = wmalloc(ccount);
color_table[1] = wmalloc(ccount);
color_table[2] = wmalloc(ccount);
color_table[3] = wmalloc(ccount);
symbol_table = wmalloc(ccount * sizeof(unsigned short));
bsize = csize * w + 16;
buffer = malloc(bsize);
buffer = wmalloc(bsize);
if (!color_table[0] || !color_table[1] || !color_table[2] ||
!color_table[3] || !symbol_table || !bsize || !buffer) {
@@ -298,7 +298,7 @@ RImage *RLoadXPM(RContext * context, const char *file)
fclose(f);
free_color_symbol_table(color_table, symbol_table);
if (buffer)
free(buffer);
wfree(buffer);
return NULL;
}
@@ -355,7 +355,7 @@ RImage *RLoadXPM(RContext * context, const char *file)
fclose(f);
free_color_symbol_table(color_table, symbol_table);
if (buffer)
free(buffer);
wfree(buffer);
return NULL;
}
@@ -434,7 +434,7 @@ RImage *RLoadXPM(RContext * context, const char *file)
fclose(f);
free_color_symbol_table(color_table, symbol_table);
if (buffer)
free(buffer);
wfree(buffer);
return image;
bad_format:
@@ -442,7 +442,7 @@ RImage *RLoadXPM(RContext * context, const char *file)
fclose(f);
free_color_symbol_table(color_table, symbol_table);
if (buffer)
free(buffer);
wfree(buffer);
if (image)
RReleaseImage(image);
return NULL;
@@ -452,7 +452,7 @@ RImage *RLoadXPM(RContext * context, const char *file)
fclose(f);
free_color_symbol_table(color_table, symbol_table);
if (buffer)
free(buffer);
wfree(buffer);
if (image)
RReleaseImage(image);
return NULL;

View File

@@ -27,6 +27,8 @@
#include <string.h>
#include <X11/Xlib.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "wr_i18n.h"
@@ -53,7 +55,7 @@ RImage *RCreateImage(unsigned width, unsigned height, int alpha)
return NULL;
}
image = malloc(sizeof(RImage));
image = wmalloc(sizeof(RImage));
if (!image) {
RErrorCode = RERR_NOMEMORY;
return NULL;
@@ -68,10 +70,10 @@ RImage *RCreateImage(unsigned width, unsigned height, int alpha)
/* the +4 is to give extra bytes at the end of the buffer,
* so that we can optimize image conversion for MMX(tm).. see convert.c
*/
image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
image->data = wmalloc(width * height * (alpha ? 4 : 3) + 4);
if (!image->data) {
RErrorCode = RERR_NOMEMORY;
free(image);
wfree(image);
image = NULL;
}
@@ -94,8 +96,8 @@ void RReleaseImage(RImage * image)
image->refCount--;
if (image->refCount < 1) {
free(image->data);
free(image);
wfree(image->data);
wfree(image);
}
}

View File

@@ -29,6 +29,8 @@
#include <errno.h>
#include <jpeglib.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -59,7 +61,7 @@ Bool RSaveJPEG(RImage *img, const char *filename, char *title)
img_depth = 3;
/* collect separate RGB values to a buffer */
buffer = malloc(sizeof(char) * 3 * img->width * img->height);
buffer = wmalloc(sizeof(char) * 3 * img->width * img->height);
for (y = 0; y < img->height; y++) {
for (x = 0; x < img->width; x++) {
RGetPixel(img, x, y, &pixel);
@@ -97,7 +99,7 @@ Bool RSaveJPEG(RImage *img, const char *filename, char *title)
jpeg_finish_compress(&cinfo);
/* Clean */
free(buffer);
wfree(buffer);
fclose(file);
return True;

View File

@@ -29,6 +29,8 @@
#include <errno.h>
#include <png.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -95,7 +97,7 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
png_write_info(png_ptr, png_info_ptr);
/* Allocate memory for one row (3 bytes per pixel - RGB) */
png_row = (png_bytep) malloc(3 * width * sizeof(png_byte));
png_row = (png_bytep) wmalloc(3 * width * sizeof(png_byte));
/* Write image data */
for (y = 0; y < height; y++) {
@@ -121,7 +123,7 @@ Bool RSavePNG(RImage *img, const char *filename, char *title)
if (png_ptr != NULL)
png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
if (png_row != NULL)
free(png_row);
wfree(png_row);
return True;
}

View File

@@ -28,6 +28,8 @@
#include <assert.h>
#include <errno.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "imgformat.h"
#include "wr_i18n.h"
@@ -95,7 +97,7 @@ static Bool addcolor(XPMColor ** list, unsigned r, unsigned g, unsigned b, int *
if (tmpc)
return True;
newc = malloc(sizeof(XPMColor));
newc = wmalloc(sizeof(XPMColor));
if (!newc) {
@@ -149,7 +151,7 @@ static void freecolormap(XPMColor * colormap)
while (colormap) {
tmp = colormap->next;
free(colormap);
wfree(colormap);
colormap = tmp;
}
}

View File

@@ -29,6 +29,8 @@
#include <math.h>
#include <assert.h>
#include <WINGs/WUtil.h>
#include "wraster.h"
#include "scale.h"
#include "wr_i18n.h"
@@ -295,7 +297,7 @@ typedef struct {
/* clamp the input to the specified range */
#define CLAMP(v,l,h) ((v)<(l) ? (l) : (v) > (h) ? (h) : v)
/* return of calloc is not checked if NULL in the function below! */
/* return of wmalloc is not checked if NULL in the function below! */
RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
{
CLIST *contrib; /* array of contribution lists */
@@ -319,13 +321,13 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
yscale = (double)new_height / (double)src->height;
/* pre-calculate filter contributions for a row */
contrib = (CLIST *) calloc(new_width, sizeof(CLIST));
contrib = (CLIST *) wmalloc(new_width * sizeof(CLIST));
if (xscale < 1.0) {
width = fwidth / xscale;
fscale = 1.0 / xscale;
for (i = 0; i < new_width; ++i) {
contrib[i].n = 0;
contrib[i].p = (CONTRIB *) calloc((int) ceil(width * 2 + 1), sizeof(CONTRIB));
contrib[i].p = (CONTRIB *) wmalloc(ceil(width * 2 + 1) * sizeof(CONTRIB));
center = (double)i / xscale;
left = ceil(center - width);
right = floor(center + width);
@@ -348,7 +350,7 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
for (i = 0; i < new_width; ++i) {
contrib[i].n = 0;
contrib[i].p = (CONTRIB *) calloc((int) ceil(fwidth * 2 + 1), sizeof(CONTRIB));
contrib[i].p = (CONTRIB *) wmalloc(ceil(fwidth * 2 + 1) * sizeof(CONTRIB));
center = (double)i / xscale;
left = ceil(center - fwidth);
right = floor(center + fwidth);
@@ -395,18 +397,18 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
/* free the memory allocated for horizontal filter weights */
for (i = 0; i < new_width; ++i) {
free(contrib[i].p);
wfree(contrib[i].p);
}
free(contrib);
wfree(contrib);
/* pre-calculate filter contributions for a column */
contrib = (CLIST *) calloc(dst->height, sizeof(CLIST));
contrib = (CLIST *) wmalloc(dst->height * sizeof(CLIST));
if (yscale < 1.0) {
width = fwidth / yscale;
fscale = 1.0 / yscale;
for (i = 0; i < dst->height; ++i) {
contrib[i].n = 0;
contrib[i].p = (CONTRIB *) calloc((int) ceil(width * 2 + 1), sizeof(CONTRIB));
contrib[i].p = (CONTRIB *) wmalloc(ceil(width * 2 + 1) * sizeof(CONTRIB));
center = (double)i / yscale;
left = ceil(center - width);
right = floor(center + width);
@@ -428,7 +430,7 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
} else {
for (i = 0; i < dst->height; ++i) {
contrib[i].n = 0;
contrib[i].p = (CONTRIB *) calloc((int) ceil(fwidth * 2 + 1), sizeof(CONTRIB));
contrib[i].p = (CONTRIB *) wmalloc(ceil(fwidth * 2 + 1) * sizeof(CONTRIB));
center = (double)i / yscale;
left = ceil(center - fwidth);
right = floor(center + fwidth);
@@ -450,7 +452,7 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
}
/* apply filter to zoom vertically from tmp to dst */
sp = malloc(tmp->height * 3);
sp = wmalloc(tmp->height * 3);
for (k = 0; k < new_width; ++k) {
CONTRIB *pp;
@@ -485,13 +487,13 @@ RImage *RSmoothScaleImage(RImage * src, unsigned new_width, unsigned new_height)
p += new_width * 3;
}
}
free(sp);
wfree(sp);
/* free the memory allocated for vertical filter weights */
for (i = 0; i < dst->height; ++i) {
free(contrib[i].p);
wfree(contrib[i].p);
}
free(contrib);
wfree(contrib);
RReleaseImage(tmp);

View File

@@ -149,10 +149,10 @@ int main(int argc, char **argv)
getchar();
free(color_name);
wfree(color_name);
for (i = 0; i < ncolors + 1; i++)
free(colors[i]);
free(colors);
wfree(colors[i]);
wfree(colors);
RDestroyContext(ctx);
RShutdown();

View File

@@ -31,6 +31,8 @@
#include <assert.h>
#include <WINGs/WUtil.h>
#ifdef USE_XSHM
#include <sys/ipc.h>
#include <sys/shm.h>
@@ -63,7 +65,7 @@ RXImage *RCreateXImage(RContext * context, int depth, unsigned width, unsigned h
RXImage *rximg;
Visual *visual = context->visual;
rximg = malloc(sizeof(RXImage));
rximg = wmalloc(sizeof(RXImage));
if (!rximg) {
RErrorCode = RERR_NOMEMORY;
return NULL;
@@ -71,14 +73,14 @@ RXImage *RCreateXImage(RContext * context, int depth, unsigned width, unsigned h
#ifndef USE_XSHM
rximg->image = XCreateImage(context->dpy, visual, depth, ZPixmap, 0, NULL, width, height, 8, 0);
if (!rximg->image) {
free(rximg);
wfree(rximg);
RErrorCode = RERR_XERROR;
return NULL;
}
rximg->image->data = malloc(rximg->image->bytes_per_line * height);
rximg->image->data = wmalloc(rximg->image->bytes_per_line * height);
if (!rximg->image->data) {
XDestroyImage(rximg->image);
free(rximg);
wfree(rximg);
RErrorCode = RERR_NOMEMORY;
return NULL;
}
@@ -90,14 +92,14 @@ RXImage *RCreateXImage(RContext * context, int depth, unsigned width, unsigned h
rximg->is_shared = 0;
rximg->image = XCreateImage(context->dpy, visual, depth, ZPixmap, 0, NULL, width, height, 8, 0);
if (!rximg->image) {
free(rximg);
wfree(rximg);
RErrorCode = RERR_XERROR;
return NULL;
}
rximg->image->data = malloc(rximg->image->bytes_per_line * height);
rximg->image->data = wmalloc(rximg->image->bytes_per_line * height);
if (!rximg->image->data) {
XDestroyImage(rximg->image);
free(rximg);
wfree(rximg);
RErrorCode = RERR_NOMEMORY;
return NULL;
}
@@ -173,7 +175,7 @@ void RDestroyXImage(RContext * context, RXImage * rximage)
XDestroyImage(rximage->image);
}
#endif
free(rximage);
wfree(rximage);
}
static unsigned getDepth(Display * dpy, Drawable d)
@@ -205,7 +207,7 @@ RXImage *RGetXImage(RContext * context, Drawable d, int x, int y, unsigned width
}
}
if (!ximg) {
ximg = malloc(sizeof(RXImage));
ximg = wmalloc(sizeof(RXImage));
if (!ximg) {
RErrorCode = RERR_NOMEMORY;
return NULL;
@@ -214,7 +216,7 @@ RXImage *RGetXImage(RContext * context, Drawable d, int x, int y, unsigned width
ximg->image = XGetImage(context->dpy, d, x, y, width, height, AllPlanes, ZPixmap);
}
#else /* !USE_XSHM */
ximg = malloc(sizeof(RXImage));
ximg = wmalloc(sizeof(RXImage));
if (!ximg) {
RErrorCode = RERR_NOMEMORY;
return NULL;
@@ -224,7 +226,7 @@ RXImage *RGetXImage(RContext * context, Drawable d, int x, int y, unsigned width
#endif /* !USE_XSHM */
if (ximg->image == NULL) {
free(ximg);
wfree(ximg);
return NULL;
}

View File

@@ -12,7 +12,6 @@ cc = "1.0"
[dependencies]
atomic-write-file = "0.3"
hashbrown = "0.16.0"
libc = "0.2.175"
nom = "8.0"
nom-language = "0.1"
x11 = "2.21.0"

View File

@@ -2,6 +2,7 @@ AUTOMAKE_OPTIONS =
RUST_SOURCES = \
src/array.rs \
src/bag.rs \
src/data.rs \
src/defines.c \
src/defines.rs \
@@ -9,7 +10,10 @@ RUST_SOURCES = \
src/hash_table.rs \
src/lib.rs \
src/memory.rs \
src/prop_list.rs
src/notification.rs \
src/prop_list.rs \
src/string.rs
src/tree.rs
RUST_EXTRA = \
Cargo.lock \

View File

@@ -204,7 +204,7 @@ pub mod ffi {
return ptr::null_mut();
}
unsafe {
(*array)
(&(*array))
.items
.get(index as usize)
.map(|p| p.as_ptr())

372
wutil-rs/src/bag.rs Normal file
View File

@@ -0,0 +1,372 @@
//! Simple sorted set.
//!
//! ## Rust rewrite notes
//!
//! This was originally a full-blown red-black tree, but it was really only used
//! to keep a sorted list. It has been rewritten as a sorted `Vec`. We
//! technically no longer have O(log(n)) insertion time. Given set sizes and
//! actual execution time, that shouldn't matter.
//!
//! Prefer a proper Rust collection over this for new code.
use std::{
ffi::{c_int, c_void},
ptr::NonNull,
};
#[derive(Default)]
pub struct Bag {
inner: Vec<(c_int, NonNull<c_void>)>,
}
/// Sentinel iterator value. In C, just check for negative values.
pub const NOT_FOUND: c_int = -1;
impl Bag {
/// Returns `Ok(index)` if an item keyed by `key` is in `self`, else
/// `Err(index)` if an item keyed by `key` could be inserted at `index`.
fn search(&self, key: c_int) -> Result<usize, usize> {
self.inner.binary_search_by_key(&key, |(key, _)| *key)
}
/// Sets a value associated with `key` to `value`. Clobbers any extant value.
fn set(&mut self, key: c_int, value: NonNull<c_void>) {
match self.search(key) {
Ok(i) => self.inner[i] = (key, value),
Err(i) => self.inner.insert(i, (key, value)),
}
}
}
pub mod ffi {
use super::{Bag, NOT_FOUND};
use std::{
ffi::{c_int, c_void},
ptr::{self, NonNull},
};
/// Basic constructor. Free with [`WMFreeBag`].
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreateTreeBag() -> *mut Bag {
Box::leak(Box::new(Bag::default()))
}
/// Retrieves the value associated with `key`, or null.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetFromBag(bag: *mut Bag, key: c_int) -> *mut c_void {
if bag.is_null() {
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
bag
.search(key)
.ok()
.and_then(|index| bag.inner.get(index).copied())
.map(|(_, value)| value.as_ptr())
.unwrap_or(ptr::null_mut())
}
/// Sets the value associated with `key` to `item`. If `item` is null,
/// removes any extant value.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMSetInBag(bag: *mut Bag, key: c_int, item: *mut c_void) {
if bag.is_null() {
return;
}
let bag = unsafe { &mut *bag };
if let Some(item) = NonNull::new(item) {
bag.set(key, item);
} else {
if let Some(i) = bag.search(key).ok() {
bag.inner.remove(i);
}
}
}
/// Clears the contents of `bag`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMEmptyBag(bag: *mut Bag) {
if bag.is_null() {
return;
}
unsafe {
(*bag).inner.clear();
}
}
/// Deletes `bag`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMFreeBag(bag: *mut Bag) {
if bag.is_null() {
return;
}
unsafe {
let _ = Box::from_raw(bag);
}
}
/// Initializes `ptr` to the first element of `bag` and returns that
/// element. Sets `ptr` to [`NOT_FOUND`] and returns null if `bag` is empty.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBagFirst(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
if ptr.is_null() {
return ptr::null_mut();
}
let ptr = unsafe { &mut *ptr };
if bag.is_null() {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
if let Some((_, value)) = bag.inner.first() {
*ptr = 0;
value.as_ptr()
} else {
*ptr = NOT_FOUND;
ptr::null_mut()
}
}
/// Initializes `ptr` to the last element of `bag` and returns that
/// element. Sets `ptr` to [`NOT_FOUND`] and returns null if `bag` is empty.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBagLast(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
if ptr.is_null() {
return ptr::null_mut();
}
let ptr = unsafe { &mut *ptr };
if bag.is_null() {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
if let Some((_, value)) = bag.inner.last() {
*ptr = (bag.inner.len() - 1) as c_int;
value.as_ptr()
} else {
*ptr = NOT_FOUND;
ptr::null_mut()
}
}
/// Advances `ptr` to the next element of `bag` and returns it. Sets `ptr`
/// to [`NOT_FOUND`] and returns null if `ptr` is already at the end of
/// `bag`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBagNext(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
if ptr.is_null() {
return ptr::null_mut();
}
let ptr = unsafe { &mut *ptr };
if bag.is_null() {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
if *ptr < 0 {
return ptr::null_mut();
}
*ptr += 1;
if let Some((_, value)) = bag.inner.get(*ptr as usize) {
value.as_ptr()
} else {
*ptr = NOT_FOUND;
ptr::null_mut()
}
}
/// Decrements `ptr` to the previous element of `bag` and returns it. Sets `ptr`
/// to [`NOT_FOUND`] and returns null if `ptr` is already at the beginning of
/// `bag`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBagPrevious(bag: *mut Bag, ptr: *mut c_int) -> *mut c_void {
if ptr.is_null() {
return ptr::null_mut();
}
let ptr = unsafe { &mut *ptr };
if bag.is_null() {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
if *ptr <= 0 {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
*ptr -= 1;
if let Some((_, value)) = bag.inner.get(*ptr as usize) {
value.as_ptr()
} else {
*ptr = NOT_FOUND;
ptr::null_mut()
}
}
/// Sets `ptr` to the element of `bag` with `key` and returns the associated
/// value. Sets `ptr` to [`NOT_FOUND`] and returns null if there is no such
/// element.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMBagIteratorAtIndex(
bag: *mut Bag,
key: c_int,
ptr: *mut c_int,
) -> *mut c_void {
if ptr.is_null() {
return ptr::null_mut();
}
let ptr = unsafe { &mut *ptr };
if bag.is_null() {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
let bag = unsafe { &mut *bag };
if key < 0 {
*ptr = NOT_FOUND;
return ptr::null_mut();
}
if let Some(index) = bag.search(key).ok() {
*ptr = index as c_int;
bag.inner[index].1.as_ptr()
} else {
*ptr = NOT_FOUND;
ptr::null_mut()
}
}
}
#[cfg(test)]
mod test {
use super::{ffi, Bag, NOT_FOUND};
use std::{
ffi::{c_int, c_void},
ptr::NonNull,
};
fn void_of<T>(t: &mut T) -> NonNull<c_void> {
NonNull::new(t as *mut _ as *mut c_void).unwrap()
}
#[test]
fn insert_out_of_order() {
let mut b = Bag::default();
let mut x = 3u16;
let mut y = 4u16;
let mut z = 5u16;
b.set(7, void_of(&mut z));
b.set(3, void_of(&mut y));
b.set(5, void_of(&mut x));
assert_eq!(
b.inner,
&[
(3, void_of(&mut y)),
(5, void_of(&mut x)),
(7, void_of(&mut z))
]
);
}
#[test]
fn iterate_forward() {
let mut b = Bag::default();
let mut x = 3u16;
let mut y = 4u16;
let mut z = 5u16;
b.set(7, void_of(&mut z));
b.set(3, void_of(&mut y));
b.set(5, void_of(&mut x));
let mut iterator: c_int = NOT_FOUND;
unsafe {
assert_eq!(
ffi::WMBagFirst(&mut b, &mut iterator),
void_of(&mut y).as_ptr()
);
assert_eq!(iterator, 0);
assert_eq!(
ffi::WMBagNext(&mut b, &mut iterator),
void_of(&mut x).as_ptr()
);
assert_eq!(iterator, 1);
assert_eq!(
ffi::WMBagNext(&mut b, &mut iterator),
void_of(&mut z).as_ptr()
);
assert_eq!(iterator, 2);
assert!(ffi::WMBagNext(&mut b, &mut iterator).is_null());
assert_eq!(iterator, NOT_FOUND);
}
}
#[test]
fn iterate_backward() {
let mut b = Bag::default();
let mut x = 3u16;
let mut y = 4u16;
let mut z = 5u16;
b.set(7, void_of(&mut z));
b.set(3, void_of(&mut y));
b.set(5, void_of(&mut x));
let mut iterator: c_int = NOT_FOUND;
unsafe {
assert_eq!(
ffi::WMBagLast(&mut b, &mut iterator),
void_of(&mut z).as_ptr()
);
assert_eq!(iterator, 2);
assert_eq!(
ffi::WMBagPrevious(&mut b, &mut iterator),
void_of(&mut x).as_ptr()
);
assert_eq!(iterator, 1);
assert_eq!(
ffi::WMBagPrevious(&mut b, &mut iterator),
void_of(&mut y).as_ptr()
);
assert_eq!(iterator, 0);
assert!(ffi::WMBagPrevious(&mut b, &mut iterator).is_null());
assert_eq!(iterator, NOT_FOUND);
}
}
#[test]
fn find_iterate() {
let mut b = Bag::default();
let mut x = 3u16;
let mut y = 4u16;
let mut z = 5u16;
b.set(7, void_of(&mut z));
b.set(3, void_of(&mut y));
b.set(5, void_of(&mut x));
let mut iterator: c_int = NOT_FOUND;
unsafe {
assert_eq!(
ffi::WMBagIteratorAtIndex(&mut b, 5, &mut iterator),
void_of(&mut x).as_ptr()
);
assert_eq!(iterator, 1);
assert_eq!(
ffi::WMBagNext(&mut b, &mut iterator),
void_of(&mut z).as_ptr()
);
assert_eq!(iterator, 2);
}
}
}

View File

@@ -1,15 +1,14 @@
use hashbrown::hash_map::{self, HashMap};
use std::{
borrow::Borrow,
ffi::{CStr, c_void},
ffi::CStr,
hash::{Hash, Hasher},
mem,
};
pub enum HashTable {
PointerKeyed(HashMap<VoidPointer, VoidPointer>),
StringKeyed(HashMap<StringPointer, VoidPointer>),
PointerKeyed(HashMap<*mut u8, *mut u8>),
StringKeyed(HashMap<StringKey, *mut u8>),
}
impl HashTable {
@@ -35,36 +34,34 @@ impl HashTable {
}
}
pub unsafe fn get(&self, key: *const i8) -> Option<*mut i8> {
pub unsafe fn get(&self, key: *const u8) -> Option<*mut u8> {
match self {
HashTable::PointerKeyed(m) => {
let key = key.cast_mut();
m.get(&key).map(|x| x.0)
m.get(&key).copied()
}
HashTable::StringKeyed(m) => {
let key = StringPointer(key.cast_mut());
let v = m.get(&key).map(|x| x.0);
mem::forget(key);
v
let key = StringKey(key.cast_mut());
m.get(&key).copied()
}
}
}
pub unsafe fn insert(&mut self, key: *mut i8, data: VoidPointer) -> Option<VoidPointer> {
pub unsafe fn insert(&mut self, key: *mut u8, data: *mut u8) -> Option<*mut u8> {
match self {
HashTable::PointerKeyed(m) => m.insert(VoidPointer(key), data),
HashTable::StringKeyed(m) => m.insert(StringPointer(key), data),
HashTable::PointerKeyed(m) => m.insert(key, data),
HashTable::StringKeyed(m) => m.insert(StringKey(key), data),
}
}
pub unsafe fn remove(&mut self, key: *const i8) {
pub unsafe fn remove(&mut self, key: *const u8) {
match self {
HashTable::PointerKeyed(m) => {
let key = key.cast_mut();
m.remove(&key);
}
HashTable::StringKeyed(m) => {
let key = StringPointer(key.cast_mut());
let key = StringKey(key.cast_mut());
m.remove(&key);
mem::forget(key);
}
@@ -72,60 +69,35 @@ impl HashTable {
}
}
#[derive(Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct VoidPointer(*mut i8);
impl Drop for VoidPointer {
fn drop(&mut self) {
unsafe { libc::free(self.0.cast::<c_void>()) }
}
}
impl Borrow<*mut i8> for VoidPointer {
fn borrow(&self) -> &*mut i8 {
&self.0
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct StringPointer(*mut i8);
pub struct StringKey(*const u8);
impl PartialEq for StringPointer {
impl PartialEq for StringKey {
fn eq(&self, other: &Self) -> bool {
match (self.0.is_null(), other.0.is_null()) {
(true, true) => true,
(true, false) => false,
(false, true) => false,
(false, false) => unsafe { CStr::from_ptr(self.0) == CStr::from_ptr(other.0) },
(false, false) => unsafe { CStr::from_ptr(self.0.cast()) == CStr::from_ptr(other.0.cast()) },
_ => false,
}
}
}
impl Eq for StringPointer {}
impl Eq for StringKey {}
impl Hash for StringPointer {
impl Hash for StringKey {
fn hash<H: Hasher>(&self, h: &mut H) {
if self.0.is_null() {
h.write_usize(0)
} else {
unsafe { CStr::from_ptr(self.0).hash(h) }
}
}
}
impl Drop for StringPointer {
fn drop(&mut self) {
unsafe {
libc::free(self.0.cast::<c_void>());
unsafe { CStr::from_ptr(self.0.cast()).hash(h) }
}
}
}
pub enum Enumerator<'a> {
PointerKeyed(hash_map::IterMut<'a, VoidPointer, VoidPointer>),
StringKeyed(hash_map::IterMut<'a, StringPointer, VoidPointer>),
PointerKeyed(hash_map::IterMut<'a, *mut u8, *mut u8>),
StringKeyed(hash_map::IterMut<'a, StringKey, *mut u8>),
}
pub mod ffi {
@@ -134,7 +106,7 @@ pub mod ffi {
mem, ptr,
};
use super::{Enumerator, HashTable, StringPointer, VoidPointer};
use super::{Enumerator, HashTable, StringKey};
#[unsafe(no_mangle)]
#[allow(non_snake_case)]
@@ -182,7 +154,7 @@ pub mod ffi {
if table.is_null() {
return ptr::null_mut();
}
let key = key.cast::<i8>();
let key = key.cast::<u8>();
(unsafe { (*table).get(key) })
.map(|v| v.cast::<c_void>())
.unwrap_or(ptr::null_mut())
@@ -201,27 +173,25 @@ pub mod ffi {
let table = unsafe { &mut *table };
match table {
HashTable::PointerKeyed(m) => {
let key = VoidPointer(key.cast::<i8>().cast_mut());
let result = match m.get_key_value_mut(&key) {
let result = match m.get_key_value_mut(&key.cast::<u8>().cast_mut()) {
Some((k, v)) => {
unsafe {
*key_dest = k.0.cast::<c_void>();
*value_dest = v.0.cast::<c_void>();
*key_dest = k.cast::<c_void>();
*value_dest = v.cast::<c_void>();
}
1
}
None => 0,
};
mem::forget(key);
result
}
HashTable::StringKeyed(m) => {
let key = StringPointer(key.cast::<i8>().cast_mut());
let key = StringKey(key.cast::<u8>().cast_mut());
let result = match m.get_key_value_mut(&key) {
Some((k, v)) => {
unsafe {
*key_dest = k.0.cast::<c_void>();
*value_dest = v.0.cast::<c_void>();
*value_dest = v.cast::<c_void>();
}
1
}
@@ -243,12 +213,8 @@ pub mod ffi {
if table.is_null() {
return ptr::null_mut();
}
match unsafe { (*table).insert(key.cast::<i8>(), VoidPointer(data.cast::<i8>())) } {
Some(v) => {
let raw = v.0;
mem::forget(v);
raw.cast::<c_void>()
}
match unsafe { (*table).insert(key.cast::<u8>(), data.cast::<u8>()) } {
Some(v) => v.cast::<c_void>(),
None => ptr::null_mut(),
}
}
@@ -260,7 +226,7 @@ pub mod ffi {
return;
}
unsafe {
(*table).remove(key.cast::<i8>());
(*table).remove(key.cast::<u8>());
}
}
@@ -298,25 +264,25 @@ pub mod ffi {
let e = unsafe { &mut *e };
match e {
Enumerator::PointerKeyed(i) => match i.next() {
Some((_, v)) => v.0.cast::<c_void>(),
Some((_, v)) => v.cast::<c_void>(),
None => ptr::null_mut(),
},
Enumerator::StringKeyed(i) => match i.next() {
Some((_, v)) => v.0.cast::<c_void>(),
Some((_, v)) => v.cast::<c_void>(),
None => ptr::null_mut(),
},
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMNextHashEnumeratorKey(e: *mut Enumerator<'static>) -> *mut c_void {
pub unsafe extern "C" fn WMNextHashEnumeratorKey(e: *mut Enumerator<'static>) -> *const c_void {
if e.is_null() {
return ptr::null_mut();
}
let e = unsafe { &mut *e };
match e {
Enumerator::PointerKeyed(i) => match i.next() {
Some((k, _)) => k.0.cast::<c_void>(),
Some((k, _)) => k.cast::<c_void>(),
None => ptr::null_mut(),
},
Enumerator::StringKeyed(i) => match i.next() {

View File

@@ -1,7 +1,11 @@
pub mod array;
pub mod bag;
pub mod data;
pub mod defines;
pub mod find_file;
pub mod hash_table;
pub mod memory;
pub mod notification;
pub mod prop_list;
pub mod string;
pub mod tree;

View File

@@ -114,7 +114,7 @@ pub mod ffi {
use std::{ffi::c_void, ptr};
/// Allocates `size` bytes. Returns null if `size` is 0. Data will be
/// initialized but have an arbitrary value.
/// initialized to 0.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wmalloc(size: usize) -> *mut c_void {
alloc_bytes(size).cast::<c_void>()

View File

@@ -0,0 +1,360 @@
use std::{
collections::{btree_map::Entry, BTreeMap},
ffi::{c_void, CStr},
ptr::{self, NonNull},
sync::Mutex,
};
// Helper function for adding the entry `(key, (observer, action))` to `map`.
fn register<K: Eq + Ord>(
map: &mut BTreeMap<K, Vec<(Option<Sendable>, Action)>>,
key: K,
observer: Option<Sendable>,
action: Action,
) {
match map.entry(key) {
Entry::Occupied(mut o) => {
o.get_mut().push((observer, action));
}
Entry::Vacant(v) => {
v.insert(vec![(observer, action)]);
}
}
}
/// Lightweight message from object to another. When a notification is sent,
/// registered [`Action`]s are called.
///
/// Use [`ffi::WMAddNotificationObserver`] or [`NotificationCenter::register`]
/// to request notifications.
///
/// ## Safety
///
/// `Notification` encapsulates two data pointers. The Rust implementation
/// explicitly supports notifications across threads. To uphold Rust's safety
/// rules, `Notification`s must only be created with pointers that can be sent
/// across threads. The [`Sendable`] struct is provided to guarantee this.
///
/// ## Rust rewrite notes
///
/// This was originally a reference-counted structure, but it is so lightweight
/// (consisting of three pointers) that the Rust version is `Copy`. This
/// simplifies things --- each Rust recipient of a `Notification` owns it, and
/// there is no need to coordinate how it is cleaned up.
///
/// In unported C code, a notificaton's `name` may be compared against a string
/// constant using pointer equality rather than string equality. This has
/// negative implications for sending notifications across the Rust/C
/// boundary. For the time being, notifications are generated and received by
/// code written in C, but care should be taken that notification names are
/// checked properly when porting notification registration in the future. (We
/// will ideally move to a different data type for identifying notifications,
/// too.)
#[derive(Clone, Copy)]
pub struct Notification {
name: &'static CStr,
/// The object that generated the notification. This may be `None` for
/// notifications that are about global state.
source: Option<Sendable>,
/// Optional side-channel data provided to notification listeners.
client_data: Option<Sendable>,
}
/// Callback that notifies `observer` (which may be null) of `notification` (which won't be).
pub type Action = unsafe extern "C" fn(observer: *mut c_void, notification: *const Notification);
/// Wraps a type-erased pointer (which it does not own) and marks it as `Send`.
///
/// The `Send`-ability of the wrapped pointer must be guaranteed by code that
/// instantiates a `Sendable`.
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
pub struct Sendable {
ptr: NonNull<c_void>,
}
impl Sendable {
/// Creates a `Sendable` wrapping `ptr`.
///
/// ## Safety
///
/// `ptr` must be safe to send across threads.
pub unsafe fn new(ptr: NonNull<c_void>) -> Self {
Sendable { ptr }
}
}
// Guaranteed by `Sendable::new`.
unsafe impl Send for Sendable {}
pub struct NotificationCenter {
/// Notification subscriptions that match on name and source.
exact: BTreeMap<(&'static CStr, Sendable), Vec<(Option<Sendable>, Action)>>,
/// Notification subscriptions that match on name.
by_name: BTreeMap<&'static CStr, Vec<(Option<Sendable>, Action)>>,
/// Notification subscriptions that match on source.
by_source: BTreeMap<Sendable, Vec<(Option<Sendable>, Action)>>,
/// Notification subscriptions that match all notifications.
universal: Vec<(Option<Sendable>, Action)>,
}
// It is safe to send NotificationCenter across threads as long as the contract
// on Sendable is respected.
unsafe impl Send for NotificationCenter {}
impl NotificationCenter {
/// Creates a new `NotificationCenter`.
pub const fn new() -> Self {
NotificationCenter {
exact: BTreeMap::new(),
by_name: BTreeMap::new(),
by_source: BTreeMap::new(),
universal: Vec::new(),
}
}
/// Provides access to the default, process-wide notification center. The
/// FFI C API uses this notification center. This is protected behind a
/// mutex that is held while `f` is run, so panicking inside of `f` should
/// be avoided.
pub fn with_global_default<R>(f: impl FnOnce(&mut Self) -> R) -> R {
static INSTANCE: Mutex<NotificationCenter> = Mutex::new(NotificationCenter::new());
f(&mut INSTANCE
.try_lock()
.unwrap())
}
/// Registers `action` to be invoked and invoked on `observer` when
/// notifications named `name` are fired from `source`.
pub fn register_exact(
&mut self,
name: &'static CStr,
source: Sendable,
observer: Option<Sendable>,
action: Action,
) {
register(&mut self.exact, (name, source), observer, action);
}
/// Registers `action` to be invoked on `observer` when notifications are
/// fired by `source` (regardless of the notification name).
pub fn register_by_source(
&mut self,
source: Sendable,
observer: Option<Sendable>,
action: Action,
) {
register(&mut self.by_source, source, observer, action);
}
/// Registers `action` to be invoked on `observer` for all notifications
/// named `name`.
pub fn register_by_name(
&mut self,
name: &'static CStr,
observer: Option<Sendable>,
action: Action,
) {
register(&mut self.by_name, name, observer, action);
}
/// Registers `action` to be invoked on `observer` for all notifications,
/// regardless of the notification's name or source.
pub fn register_universal(&mut self, observer: Option<Sendable>, action: Action) {
self.universal.push((observer, action));
}
/// Dispatches `notification` with registered actions.
pub fn dispatch(&mut self, notification: Notification) {
if let Some(observers) = self.by_name.get_mut(notification.name) {
for (observer, action) in observers {
let observer = observer.map(|x| x.ptr.as_ptr()).unwrap_or(ptr::null_mut());
unsafe {
(action)(observer, &notification);
}
}
}
if let Some(source) = notification.source {
if let Some(observers) = self.exact.get_mut(&(notification.name, source)) {
for (observer, action) in observers {
let observer = observer.map(|x| x.ptr.as_ptr()).unwrap_or(ptr::null_mut());
unsafe {
(action)(observer, &notification);
}
}
}
if let Some(observers) = self.by_source.get_mut(&source) {
for (observer, action) in observers {
let observer = observer.map(|x| x.ptr.as_ptr()).unwrap_or(ptr::null_mut());
unsafe {
(action)(observer, &notification);
}
}
}
}
for (observer, action) in &mut self.universal {
let observer = observer.map(|x| x.ptr.as_ptr()).unwrap_or(ptr::null_mut());
unsafe {
(action)(observer, &notification);
}
}
}
/// Removes all notification subscriptions that would notify `observer` if they fired.
pub fn remove_observer(&mut self, observer: Sendable) {
self.exact.retain(|_, values| {
values.retain(|(o, _)| *o != Some(observer));
!values.is_empty()
});
self.by_name.retain(|_, values| {
values.retain(|(o, _)| *o != Some(observer));
!values.is_empty()
});
self.by_source.retain(|_, values| {
values.retain(|(o, _)| *o != Some(observer));
!values.is_empty()
});
self.universal.retain(|(o, _)| *o != Some(observer));
}
/// Clears all registered notification listeners and resets `self` to its
/// default state.
pub fn clear(&mut self) {
*self = Self::new();
}
}
pub mod ffi {
use super::{Action, Notification, NotificationCenter, Sendable};
use std::{
ffi::{c_char, c_void, CStr},
ptr::{self, NonNull},
};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetNotificationClientData(
notification: *mut Notification,
) -> *mut c_void {
if notification.is_null() {
return ptr::null_mut();
}
unsafe {
(*notification)
.client_data
.map(|x| x.ptr.as_ptr())
.unwrap_or(ptr::null_mut())
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetNotificationObject(
notification: *mut Notification,
) -> *mut c_void {
if notification.is_null() {
return ptr::null_mut();
}
unsafe {
(*notification)
.source
.map(|x| x.ptr.as_ptr())
.unwrap_or(ptr::null_mut())
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetNotificationName(
notification: *mut Notification,
) -> *const c_char {
if notification.is_null() {
return ptr::null_mut();
}
unsafe { (*notification).name.as_ptr() }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMAddNotificationObserver(
action: Option<Action>,
observer: *mut c_void,
name: *const c_char,
object: *mut c_void,
) {
let Some(action) = action else {
return;
};
let observer = NonNull::new(observer).map(|x| unsafe { Sendable::new(x) });
let source = NonNull::new(object);
NotificationCenter::with_global_default(|c| {
if name.is_null() {
match source {
Some(source) => {
c.register_by_source(unsafe { Sendable::new(source) }, observer, action);
}
None => c.register_universal(observer, action),
}
} else {
let name = unsafe { CStr::from_ptr(name) };
match source {
Some(source) => {
c.register_exact(name, unsafe { Sendable::new(source) }, observer, action);
}
None => c.register_by_name(name, observer, action),
}
}
});
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMRemoveNotificationObserver(observer: *mut c_void) {
let Some(observer) = NonNull::new(observer) else {
return;
};
NotificationCenter::with_global_default(|c| {
c.remove_observer(unsafe { Sendable::new(observer) })
});
}
/// Posts a notification from `object` with the given `name` and `client_data`.
///
/// ## Safety
///
/// `name` must be a non-null string constant or some other pointer with a
/// static lifetime.
///
/// `object` and `client_data` must be safe to send across threads (per the
/// contract of [`Sendable`]).
///
/// ## Rust rewrite notes
///
/// This originally took a heap-allocated `*mut Notification`, but now the
/// constructed `Notification` parameters are passed directly.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMPostNotificationName(
name: *const c_char,
object: *mut c_void,
client_data: *mut c_void,
) {
if name.is_null() {
return;
}
let name = unsafe { CStr::from_ptr(name) };
let source = NonNull::new(object).map(|x| unsafe { Sendable::new(x) });
let client_data = NonNull::new(client_data).map(|x| unsafe { Sendable::new(x) });
NotificationCenter::with_global_default(|c| {
c.dispatch(Notification {
name,
source,
client_data,
})
});
}
/// Resets all notifications for the global notification center. Used by
/// `WApplication` teardown code. This is a private, WINGs-internal API.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn W_ClearNotificationCenter() {
NotificationCenter::with_global_default(|c| c.clear());
}
}

439
wutil-rs/src/string.rs Normal file
View File

@@ -0,0 +1,439 @@
//! String manipulation utilities.
//!
//! ## Rust rewrite notes
//!
//! These are more or less bug-for-bug reimplementations of the original WUtils
//! functions. Avoid using these functions in new code.
use std::{
ffi::{c_char, c_int, CStr},
iter, mem, ptr, slice,
};
use crate::memory::{alloc_bytes, alloc_string, ffi::wrealloc, free_bytes};
/// Returns a `wmalloc`-managed C-style string that duplicates `s`, which cannot
/// be null.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wstrdup(s: *const c_char) -> *mut c_char {
assert!(!s.is_null());
alloc_string(unsafe { CStr::from_ptr(s) })
}
/// Returns a `wmalloc`-managed C-style string of the first `len` bytes of `s`,
/// which cannot be null.
///
/// If `len` exceeds the length of `s`, uses the lesser value.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wstrndup(s: *const c_char, len: usize) -> *mut c_char {
assert!(!s.is_null());
let len = unsafe {
slice::from_raw_parts(s, len)
.into_iter()
.position(|p| *p == 0)
.unwrap_or(len)
};
let copy: *mut c_char = alloc_bytes(len + 1).cast(); // Implicitly zeroed.
unsafe {
ptr::copy_nonoverlapping(s, copy, len);
}
copy.cast::<c_char>()
}
/// Concatenates `s1` and `s2` into a `wmalloc`-managed C-style string.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wstrconcat(s1: *const c_char, s2: *const c_char) -> *mut c_char {
match (s1.is_null(), s2.is_null()) {
(true, true) => ptr::null_mut(),
(true, false) => unsafe { wstrdup(s1) },
(false, true) => unsafe { wstrdup(s2) },
(false, false) => unsafe {
let s1 = CStr::from_ptr(s1);
let l1 = s1.count_bytes();
let s2 = CStr::from_ptr(s2);
let l2 = s2.count_bytes();
let s: *mut c_char = alloc_bytes(l1 + l2 + 1).cast(); // Implicitly zeroed.
ptr::copy_nonoverlapping(s1.as_ptr(), s, l1);
ptr::copy_nonoverlapping(s2.as_ptr(), s.offset(l1 as isize), l2);
s
},
}
}
/// Appends `src` to `dest`, destructively reallocating `dest` and returning a
/// new `wmalloc`-managed pointer where the result is stored. `dst` must come
/// from `wmalloc` or `wrealloc`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wstrappend(dst: *mut c_char, src: *const c_char) -> *mut c_char {
if src.is_null() {
return dst;
}
let src = unsafe { CStr::from_ptr(src) };
let src_len = src.count_bytes();
if src_len == 0 {
return dst;
}
if dst.is_null() {
return unsafe { wstrdup(src.as_ptr()) };
}
let dst_len = unsafe { CStr::from_ptr(dst).count_bytes() + 1 };
let len = dst_len + src_len + 1;
let result: *mut c_char = unsafe { wrealloc(dst.cast(), len).cast() };
unsafe {
ptr::copy_nonoverlapping(
src.as_ptr(),
result.offset(dst_len.try_into().unwrap()),
src_len,
);
}
result
}
/// Strips leading and trailing whitespace from `s`, returning a
/// `wmalloc`-managed C-style string holding the result.
///
/// ## Rust rewite notes
///
/// This uses a slightly different notion of "space character" than the original
/// C implementation did. `s` must be valid UTF-8.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wtrimspace(s: *const c_char) -> *mut c_char {
if s.is_null() {
return ptr::null_mut();
}
let Ok(s) = (unsafe { CStr::from_ptr(s).to_str() }) else {
// TODO: complain.
return ptr::null_mut();
};
let trimmed = s.trim();
let ptr = trimmed.as_ptr();
let len = trimmed.len();
unsafe { wstrndup(ptr, len) }
}
/// Splits `command` into tokens with approximately the same rules as used in
/// the shell for splitting up a command into program arguments.
fn tokensplit(command: &[u8]) -> Vec<Vec<u8>> {
enum Mode {
Start,
Unquoted(Vec<u8>),
Escape(Context),
Quoted { token: Vec<u8>, delimiter: u8, },
}
enum Context {
Unquoted(Vec<u8>),
Quoted { token: Vec<u8>, delimiter: u8, },
}
let mut out = Vec::new();
let mut mode = Mode::Start;
for &b in command {
mode = match (mode, b) {
(Mode::Start, b'\\') => Mode::Escape(Context::Unquoted(vec![])),
(Mode::Start, b'\'' | b'"') => Mode::Quoted { token: vec![], delimiter: b },
(Mode::Start, b' ' | b'\t') => Mode::Start,
(Mode::Start, _) => Mode::Unquoted(vec![b]),
(Mode::Unquoted(token), b'\\') => Mode::Escape(Context::Unquoted(token)),
(Mode::Unquoted(token), b'\'' | b'"') => Mode::Quoted { token, delimiter: b },
(Mode::Unquoted(token), b' ' | b'\t') => {
out.push(token);
Mode::Start
}
(Mode::Unquoted(mut token), _) => {
token.push(b);
Mode::Unquoted(token)
}
(Mode::Escape(Context::Unquoted(mut token)), _) => {
token.push(b);
Mode::Unquoted(token)
}
(Mode::Escape(Context::Quoted { mut token, delimiter }), _) => {
token.push(b);
Mode::Quoted { token, delimiter }
}
(Mode::Quoted { token, delimiter }, _) if b == delimiter => {
Mode::Unquoted(token)
}
(Mode::Quoted { token, delimiter }, _) if b == b'\\' => {
Mode::Escape(Context::Quoted { token, delimiter })
}
(Mode::Quoted { mut token, delimiter }, _) => {
token.push(b);
Mode::Quoted { token, delimiter }
}
}
}
match mode {
Mode::Start => (),
Mode::Unquoted(token) => out.push(token),
Mode::Quoted { token, .. } => out.push(token),
Mode::Escape(Context::Unquoted(token)) => out.push(token),
Mode::Escape(Context::Quoted { token, .. }) => out.push(token),
}
out
}
/// Splits `command` into tokens, storing the number of tokens in `argc` and
/// `wmalloc`-managed C-style strings for each token in `argv`. Call
/// [`wtokenfree`] to free `argv`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wtokensplit(
command: *const c_char,
argv: *mut *mut *mut c_char,
argc: *mut c_int,
) {
if argv.is_null() || argc.is_null() {
return;
}
unsafe {
*argv = ptr::null_mut();
*argc = 0;
}
if command.is_null() {
return;
}
let command = unsafe { CStr::from_ptr(command) };
let Ok(command) = command.to_str() else {
return;
};
let tokens = tokensplit(command.as_bytes());
if tokens.is_empty() {
return;
}
let argv = unsafe {
*argv = alloc_bytes(mem::size_of::<*mut c_char>() * tokens.len()).cast::<*mut c_char>();
*argc = tokens.len() as c_int;
slice::from_raw_parts_mut(*argv, tokens.len())
};
for (dest, mut token) in argv.iter_mut().zip(tokens.into_iter()) {
token.push(b'\0');
*dest = alloc_string(unsafe { CStr::from_bytes_with_nul_unchecked(&token) });
}
}
/// Frees an `argv` populated by [`wtokensplit`].
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wtokenfree(tokens: *mut *mut c_char, count: c_int) {
if tokens.is_null() {
return;
}
if count > 0 {
let tokens = unsafe { slice::from_raw_parts_mut(tokens, count as usize) };
for token in tokens {
unsafe {
free_bytes(*token);
}
}
}
unsafe {
free_bytes(tokens.cast::<u8>());
}
}
/// Joins the tokens of the `count` elements of `list` into a single string,
/// enclosing them in double quotes (`"`) if necessary. Returns a
/// `wmalloc`-managed C-style string with the result, or null on failure.
///
/// ## Rust rewrite notes
///
/// `list` must consist of valid UTF-8 strings. This reimplementation does not
/// attempt to improve on the original, so it has bad failure modes (like not
/// escaping quotes in the input). Do not use this function in new code.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wtokenjoin(list: *const *const char, count: c_int) -> *mut c_char {
if list.is_null() || count <= 0 {
return alloc_string(c"");
}
let list = unsafe {
slice::from_raw_parts(list.cast::<*const u8>(), count as usize)
};
let mut buffer = Vec::new();
for term in list {
if term.is_null() {
continue;
}
let term = unsafe { CStr::from_ptr(*term) };
if term.is_empty() {
continue;
}
if !buffer.is_empty() {
buffer.push(b' ');
}
let term = term.to_bytes();
if term.iter().find(|&&x| x == b' ' || x == b'\t').is_some() {
buffer.push(b'"');
buffer.extend_from_slice(term);
buffer.push(b'"');
} else {
buffer.extend_from_slice(term);
}
}
buffer.push(b'\0');
if let Ok(buffer) = CStr::from_bytes_until_nul(&buffer) {
alloc_string(buffer)
} else {
return ptr::null_mut();
}
}
#[cfg(test)]
mod test {
use super::{wtokenfree, wtokensplit, wtokenjoin};
use std::{ffi::{c_char, c_int, CStr}, ptr, slice};
#[test]
fn split_empty_whitespace() {
let mut argv = ptr::null_mut();
let mut argc = 0;
unsafe { wtokensplit(c"".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 0);
assert_eq!(argv, ptr::null_mut());
unsafe { wtokenfree(argv, argc); }
unsafe { wtokensplit(c" ".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 0);
assert_eq!(argv, ptr::null_mut());
unsafe { wtokenfree(argv, argc); }
unsafe { wtokensplit(c" \t ".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 0);
assert_eq!(argv, ptr::null_mut());
unsafe { wtokenfree(argv, argc); }
unsafe { wtokensplit(c" \t ".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 0);
assert_eq!(argv, ptr::null_mut());
unsafe { wtokenfree(argv, argc); }
unsafe { wtokensplit(c"\t\t".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 0);
assert_eq!(argv, ptr::null_mut());
unsafe { wtokenfree(argv, argc); }
}
fn args_of(argv: *mut *mut u8, argc: usize) -> Vec<String> {
let mut v = Vec::with_capacity(argc);
for s in unsafe { slice::from_raw_parts(argv, argc) } {
if s.is_null() {
return v;
}
v.push(String::from(unsafe { CStr::from_ptr(*s) }.to_str().unwrap()));
}
v
}
#[test]
fn split_empty_quoted() {
let mut argv = ptr::null_mut();
let mut argc = 0;
unsafe { wtokensplit(c"\"\"".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("")]);
unsafe { wtokenfree(argv, argc); }
argv = ptr::null_mut();
argc = 0;
unsafe { wtokensplit(c"''".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("")]);
unsafe { wtokenfree(argv, argc); }
argv = ptr::null_mut();
argc = 0;
unsafe { wtokensplit(c" ''\t".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("")]);
unsafe { wtokenfree(argv, argc); }
}
#[test]
fn split_one_unquoted() {
let mut argv = ptr::null_mut();
let mut argc = 0;
unsafe { wtokensplit(c"hello".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("hello")]);
unsafe { wtokensplit(c"hello\\\\".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("hello\\")]);
}
#[test]
fn split_one_quoted() {
let mut argv = ptr::null_mut();
let mut argc = 0;
unsafe { wtokensplit(c"\"hello\"".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("hello")]);
unsafe { wtokensplit(c"\"hello world\"".as_ptr(), &mut argv, &mut argc); }
assert_eq!(argc, 1);
assert_eq!(args_of(argv, argc as usize), vec![String::from("hello world")]);
}
#[test]
fn split_multi() {
let mut argv = ptr::null_mut();
let mut argc = 0;
unsafe {
wtokensplit(
c"\"hello world\" what\\'s happening' here it\\'s weird'".as_ptr(),
&mut argv,
&mut argc,
);
}
assert_eq!(argc, 3);
assert_eq!(args_of(argv, argc as usize), vec![String::from("hello world"),
String::from("what's"),
String::from("happening here it's weird")]);
}
/// Calls `f(wtokenjoin(list))` transparently.
fn with_list<R>(list: &[&CStr], f: impl FnOnce(Option<&CStr>) -> R) -> R {
let list: Vec<_> = list.iter().map(|s| s.as_ptr().cast::<c_char>()).collect();
let joined = unsafe { wtokenjoin(list.as_slice().as_ptr().cast(), list.len() as c_int) };
let result = f(if joined.is_null() { None } else { unsafe { Some(CStr::from_ptr(joined)) } });
unsafe { crate::memory::free_bytes(joined.cast()); }
result
}
#[test]
fn join_nothing() {
with_list(&[], |joined| {
assert_eq!(joined.unwrap(), c"");
});
with_list(&[c"", c""], |joined| {
assert_eq!(joined.unwrap(), c"");
});
}
#[test]
fn join_basic() {
with_list(&[c"hello", c"world"], |joined| {
assert_eq!(joined.unwrap(), c"hello world");
});
}
#[test]
fn join_quoted() {
with_list(&[c"hello", c"there world"], |joined| {
assert_eq!(joined.unwrap(), c"hello \"there world\"");
});
}
}

252
wutil-rs/src/tree.rs Normal file
View File

@@ -0,0 +1,252 @@
//! N-ary tree structure.
//!
//! ## Rust rewrite notes
//!
//! This is only used in one place (`util/wmmenugen.c`), and it should probably
//! be moved out of wutil-rs (if not deleted entirely) once we migrate that
//! utility.
//!
//! The FFI functions provided here assume that they will be used as they are in
//! `wmmenugen.c`. (For example, the C interface may allow for some callback
//! parameters to be null, but they aren't in practice, so the Rust layer
//! doesn't check for that.)
//!
//! The original C library had a larger surface area and tracked parent
//! pointers, but the Rust version only has the API used by wmmenugen. Case in
//! point: `WMTreeNode` originally had an optional destructor function pointer
//! for freeing its `data` field, but wmmenugen never actually deleted a tree
//! node, so the destructor was never called. This Rust rewrite doesn't track a
//! `data` destructor and doesn't even provide a way to delete tree nodes.
//!
//! If a generic tree really becomes necessary, [`Tree`] may be adapted, but a
//! different design is probably warranted. (At the very least, `Tree` should be
//! generic over the type of `data` so that we're not using `c_void`. It is also
//! probably better to index into an owned `Vec` or use an external
//! arena. `GhostCell` or one of its ilk may even make sense.)
use std::ffi::c_void;
pub struct Tree {
depth: u32,
children: Vec<Box<Tree>>,
data: *mut c_void,
}
pub mod ffi {
use super::Tree;
use std::{
ffi::{c_int, c_void},
ptr,
};
/// Creates the root of a new tree with the data `data`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMCreateTreeNode(data: *mut c_void) -> *mut Tree {
Box::leak(Box::new(Tree {
depth: 0,
children: Vec::new(),
data,
}))
}
/// Creates a tree node as the `index`th child of `parent`, with the data
/// `item`. If `index` is negative, the node is added as the last child of
/// `parent`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMInsertItemInTree(
parent: *mut Tree,
index: c_int,
item: *mut c_void,
) -> *mut Tree {
if parent.is_null() {
return ptr::null_mut();
}
let parent = unsafe { &mut *parent };
let child = Tree {
depth: parent.depth + 1,
children: Vec::new(),
data: item,
};
if index < 0 {
parent.children.push(Box::new(child));
parent.children.last_mut().unwrap().as_mut() as *mut _
} else {
let index = index as usize;
parent.children.insert(index, Box::new(child));
parent.children[index].as_mut() as *mut _
}
}
/// Inserts `tree` as the `index`th child of `parent`. If `index` is
/// negative, `tree` is added as the last child of `parent`.
///
/// This eagerly updates the depth of the entire subtree rooted at `tree`,
/// so it has a O(N) cost rather than O(1).
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMInsertNodeInTree(
parent: *mut Tree,
index: c_int,
tree: *mut Tree,
) -> *mut Tree {
if parent.is_null() {
return ptr::null_mut();
}
let parent = unsafe { &mut *parent };
if tree.is_null() {
return ptr::null_mut();
}
let mut stack = vec![(unsafe { &mut *tree }, parent.depth + 1)];
while let Some((tree, depth)) = stack.pop() {
tree.depth = depth;
for child in &mut tree.children {
stack.push((child, depth + 1));
}
}
if index < 0 {
parent.children.push(unsafe { Box::from_raw(tree) });
tree
} else {
let index = index as usize;
parent
.children
.insert(index, unsafe { Box::from_raw(tree) });
tree
}
}
/// Returns the data field of `tree`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetDataForTreeNode(tree: *mut Tree) -> *mut c_void {
if tree.is_null() {
return ptr::null_mut();
}
unsafe { (*tree).data }
}
/// Returns the depth of `tree` (0 if `tree` is a root, 1 if it is an
/// immediate child of the root, etc.). This is an `O(1)` operation.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMGetTreeNodeDepth(tree: *mut Tree) -> c_int {
if tree.is_null() {
return 0;
}
unsafe { (*tree).depth as c_int }
}
/// Recursively sorts the children of each node of the subtree rooted at
/// `tree`, according to `comparer`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMSortTree(
tree: *mut Tree,
comparer: unsafe extern "C" fn(*const Tree, *const Tree) -> c_int,
) {
use std::cmp::Ordering;
if tree.is_null() {
return;
}
let comparer = |a: &Box<Tree>, b: &Box<Tree>| {
let a = a.as_ref() as *const Tree as *const _;
let b = b.as_ref() as *const Tree as *const _;
match unsafe { comparer(a, b) }.signum() {
-1 => Ordering::Less,
0 => Ordering::Equal,
1 => Ordering::Greater,
_ => unreachable!(),
}
};
let mut stack = vec![unsafe { &mut *tree }];
while let Some(tree) = stack.pop() {
tree.children.sort_by(comparer);
stack.extend(tree.children.iter_mut().map(|c| c.as_mut()));
}
}
/// Returns the first tree node in the subtree rooted at `tree` that matches
/// `match_p`, or null if none is found. If `match_p` is `None`, returns
/// the first node whose `data` field is equal to `cdata`. Search is
/// recursive, up to `limit` depth (which must be non-negative).
///
/// ## Rust rewrite notes
///
/// This was originally a DFS with a `depthFirst` parameter which actually
/// controlled whether tree traversal was pre- or post-order (and not
/// whether the search was depth-first or breadth-first, which the name
/// might seem to suggest). Since this was only ever called with a non-zero
/// `depthFirst`, the Rust version is hard-coded as a pre-order DFS.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMFindInTreeWithDepthLimit(
tree: *mut Tree,
match_p: Option<unsafe extern "C" fn(*const Tree, *const c_void) -> c_int>,
cdata: *mut c_void,
limit: c_int,
) -> *mut Tree {
if tree.is_null() {
return ptr::null_mut();
}
let safe_tree = unsafe { &mut *tree };
let match_p = |t: &Tree| -> bool {
if let Some(p) = match_p {
(unsafe { (p)(t, cdata) }) != 0
} else {
t.data == cdata
}
};
let mut stack = vec![(safe_tree, 0)];
while let Some((tree, depth)) = stack.pop() {
if depth > limit {
continue;
}
if match_p(tree) {
return tree as *mut Tree;
}
for child in tree.children.iter_mut() {
stack.push((child.as_mut(), depth + 1));
}
}
ptr::null_mut()
}
/// Traverses `tree` recursively, invoking `walk` on each tree node with
/// `cdata` passed in to provide a side channel.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn WMTreeWalk(
tree: *mut Tree,
walk: unsafe extern "C" fn(*mut Tree, *mut c_void),
cdata: *mut c_void,
) {
if tree.is_null() {
return;
}
let tree = unsafe { &mut *tree };
let walk_fn = |t: &mut Tree| unsafe {
walk(t as *mut Tree, cdata);
};
let mut stack = vec![tree];
while let Some(tree) = stack.pop() {
walk_fn(tree);
for child in &mut tree.children {
stack.push(child);
}
}
}
}