Wrapping libcups C library in Swift - swift

I am trying to wrap the libcups library https://github.com/apple/cups to be used in my Swift project.
I have tried some of the examples in https://www.cups.org/doc/cupspm.html and they are working fine.
However I am struggling when it comes to wrapping the C code to be used in a Swift project.
I have been searching online on how to wrap C libraries in Swift but has not been able to have much progress.
Here is the C code
#include <stdio.h>
#include <cups/cups.h>
typedef struct {
int num_dests;
cups_dest_t *dests;
} my_user_data_t;
int my_dest_cb(my_user_data_t *user_data, unsigned flags, cups_dest_t *dest) {
if (flags & CUPS_DEST_FLAGS_REMOVED) {
user_data->num_dests = cupsRemoveDest(dest->name, dest->instance, user_data->num_dests, &(user_data->dests));
} else {
user_data->num_dests = cupsCopyDest(dest, user_data->num_dests, &(user_data->dests));
}
return 1;
}
int my_get_dests(cups_ptype_t type, cups_ptype_t mask, cups_dest_t **dests) {
my_user_data_t user_data = { 0, NULL };
if (!cupsEnumDests(CUPS_DEST_FLAGS_NONE, 1000, NULL, type, mask, (cups_dest_cb_t)my_dest_cb, &user_data)) {
cupsFreeDests(user_data.num_dests, user_data.dests);
*dests = NULL;
return 0;
} else {
*dests = user_data.dests;
return user_data.num_dests;
}
}
int main(int argc, const char * argv[]) {
cups_dest_t *dests = NULL;
int num_dests = my_get_dests(0, 0, &dests);
printf("Destination found: %d\n", num_dests);
cups_dest_t *dest;
int i;
const char *value;
for (i = num_dests, dest = dests; i > 0; i--, dest++) {
if (dest->instance == NULL) {
value = cupsGetOption("printer-info", dest->num_options, dest->options);
printf("%s (%s)\n", dest->name, value ? value : "No description");
}
}
return 0;
}
Here is the same thing but in Swift
let destinationsCallback: cups_dest_cb_t = { user_data, flags, dest in
// (void *user_data, unsigned flags, cups_dest_t *dest)
var userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self).pointee
var destData = dest!.pointee
if destData.instance != nil {
print("\(String(cString: destData.name))/\(String(cString: destData.instance))")
} else {
print(String(cString: destData.name))
}
if flags == CUPS_DEST_FLAGS_REMOVED {
userDataPointer.num_dests = cupsRemoveDest(destData.name, destData.instance, userDataPointer.num_dests, &(userDataPointer.dests))
} else {
userDataPointer.num_dests = cupsCopyDest(dest, userDataPointer.num_dests, &(userDataPointer.dests))
}
return 1
}
func getDestinations(type: UInt32, mask: UInt32, dests: UnsafeMutablePointer<cups_dest_t>) -> Int32 {
var userData = my_user_data_t(num_dests: 0, dests: nil)
if cupsEnumDests(UInt32(CUPS_DEST_FLAGS_NONE), 1000, nil, type, mask, destinationsCallback, &userData) != 1 {
return 0
} else {
return userData.num_dests
}
}
I am not able to get the userData to return the correct value which I am assuming is due to the way I handle the pointers.
Greatly appreciate if I am able to get some advice.

IMHO the best way to work with such C libraries in Swift is to work with them in Objective-C. Nevertheless, the main issue seems to be that you are not writing back changes to userData, that's why you always get your initial value. You need to update it in your callback like this
let userDataPointer = user_data!.assumingMemoryBound(to: my_user_data_t.self)
var userData = userDataPointer.pointee
...
// make some changes to userData
userDataPointer.pointee = userData
return 1
Also there seems to be some differences between your C code and the Swift one, like checking flags with 'flags == CUPS_DEST_FLAGS_REMOVED' which, in general, is incorrect way to check flags, and comparing result of cupsEnumDests with 1 when in the original code you check that result is not 0.

Related

How can I handle raw bytes on dart?

I'm totally new at app developing.
I trying to communicate with C-written end device via raw UDP packet. (such a modbus-like protocol)
And I'm suffering pain with serial/deserializing class(struct).
Here is a simple class, Packet which contain uint32, uint16, uint8.
Pack() is working, but are there any better way to achieve that?
I don't know how can I implement Unpack() method. I mean, how can I convert Uint8List to int?
import 'dart:typed_data';
void main() {
var pkt = new Packet();
pkt.TID = 0x01234567;
pkt.Src = 0x89;
pkt.Des = 0xab;
pkt.Data = 0xcdef;
var buf = pkt.Pack();
print('Packed: ${buf}');
var pkt_2 = new Packet();
if (pkt_2.Unpack(buf) != null) {
print("panic!");
return;
}
print('UnPacked: ${pkt_2.toString()}');
}
class Packet {
int TID; // uint32
int Src; // uint8
int Des; // uint8
int Data; // uint16
static const SIZE = 8;
String toString() {
return 'TID: ${TID.toRadixString(16)}, Src:${Src.toRadixString(16)}, Des:${Des.toRadixString(16)}, Data:${Data.toRadixString(16)}';
}
Uint8List Pack() {
var buf = Byteconv.itou32(TID) +
Byteconv.itou8(Src) +
Byteconv.itou8(Des) +
Byteconv.itou16(Data);
return Uint8List.fromList(buf);
}
Error Unpack(Uint8List buf) {
if (buf.length != SIZE) {
return Error();
}
// What can I do?
// TID =
// Src =
// Des =
// Data =
return null;
}
}
class Byteconv {
static Uint8List itou64(int val) {
return Uint8List(8)..buffer.asByteData().setUint64(0, val, Endian.big);
}
static Uint8List itou32(int val) {
return Uint8List(4)..buffer.asByteData().setUint32(0, val, Endian.big);
}
static Uint8List itou16(int val) {
return Uint8List(2)..buffer.asByteData().setUint16(0, val, Endian.big);
}
static Uint8List itou8(int u8) {
return Uint8List(1)..buffer.asUint8List()[0] = u8;
}
}
SOLVED
var buf_view = ByteData.sublistView(buf);
TID = buf_view.getUint32(0);
Src = buf_view.getUint8(4);
Des = buf_view.getUint8(5);
Data = buf_view.getUint16(6);

How to fix both Found 'DD'-anomaly and only one return statement

I have some difficulties when fixing PMD warnings, this was my simplified method:
public String rank(String keyword, int pageSize, int totalPage)
{
String result = "0"; // A: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'result'
if (isNotBlank(keyword))
{
boolean find = false; // B: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'find'
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
find = true; // B(1)
result = String.valueOf(rank); // A(1)
break;
}
}
if (!find)
{
result = format("{0}+", totalPage * pageSize - 1); // A(2)
}
}
return result;
}
I tried this and got "OnlyOneReturn" warnings:
public String rank(String keyword, int pageSize, int totalPage)
{
if (isNotBlank(keyword))
{
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
return String.valueOf(rank); // OnlyOneReturn
}
}
return format("{0}+", totalPage * pageSize - 1); // OnlyOneReturn
}
return "0";
}
How do I have to write this code please?
A 'DD'-anomaly an a dataflow analysis tells you that you assign a variable more than once without using it between the assignments. So all but the last assignment are unnecessary. It usually indicates that you didn't separate your scenarios properly. In your case you have three scenarios:
If the keyword is blank then the return value is "0".
Otherwise loop through all pages and if getRank() returns a rank other than zero then this is the return value.
Otherwise the return value is "totalPage * pageSize - 1+"
If you implement those scenarios one by one you end up with a method that has not any dataflow or other PMD issues:
public String rank(String keyword, int pageSize, int totalPage) {
String result;
if (isNotBlank(keyword)) {
result = "0";
} else {
int rank = 0;
for (int page = 1; page < totalPage && rank == 0; page++) {
rank = getRank(keyword, pageSize, totalPage);
}
if (rank != 0) {
result = String.valueOf(rank);
} else {
result = format("{0}+", totalPage * pageSize - 1);
}
}
return result;
}
If you take a closer look at the for loop you see that page is only used for looping. It is not used inside the loop. This indicates that the for loop is probably not necessary. getRank(keyword, pageSize, totalPage) should always return the same value as its arguments never change during the loop. So it might be enough to call getRank(...) just once.

Swift 5 : how to deallocate memory, allocated by shared library

I have the following C function inside a shared library :
int GetRxDataBlock( char** data )
{
CHECK_FACADE_INITIALIZATION( "getRxDataBlock : Client facade not initialized", __LINE__ );
if ( data == nullptr ) {
printErrorMsg("getRxDataBlock : nullptr", __LINE__);
return -1;
}
int ret = 0;
try {
std::string rxData = g_facade.value()->getRxDataBlock();
*data = (char*) malloc(rxData.size() + 1);
memset(*data, 0, rxData.size() + 1 );
memcpy(*data, rxData.c_str(), rxData.size());
}catch(...) {
ret = -1;
}
return ret;
}
And this is the way I call it from Swift code :
var rxData: UnsafeMutablePointer? = nil
let apiResponse = GetRxDataBlock(&rxData)
print("Rx data : ret = \(apiResponse)")
if let dataStr = rxData {
let rxStr = String(cString: dataStr)
print("Rx data = \(rxStr)")
}
What is the correct way to deallocate memory returned by GetRxDataBlock function ?
malloc()ed memory must be released with free():
if let dataStr = rxData {
// do something with `dataStr`
// ...
free(dataStr)
}
This is also a good use-case for defer, which calls the closure just before the scope of the block is left:
if let dataStr = rxData {
defer { free(dataStr) }
// do something with `dataStr`
// ...
}
On Apple platforms, free() is imported from the standard C library as part of the Darwin module (which is imported by Foundation, AppKit, or UIKit). On Linux you would import Glibc.

C++ overloading operator, compiler doesn't see the operator

CMagazin.h
class CMagazin
{
char *m_nume;
list<CProdus*>List_produse;
public:
void printExpirabile( const char* data);
~CMagazin();
};
CMagazin.cpp
void CMagazin::printExpirabile(const char *xdata)
{
list<CProdus*>::iterator it;
for (it = List_produse.begin(); it != List_produse.end(); ++it)
{
CProdus* p = *it;
if (p->get_tip()=='A')
{
**if (p > xdata)**->this problem
}
}
}
CAliment.h
class CAliment :
public CProdus
{
char *m_expirare;
public:
bool operator >(const char*date);
~CAliment();
};
CAliment.cpp
bool CAliment::operator>(const char * date)
{
if (atoi(this->m_expirare) < atoi(date))
{
return 1;
}
else
{
return 0;
}
}
its about ">" operator.in CMagazin.cpp dont use my operator...i need help.
what can i do?I need ">" in CMagazin class. class CAliment its a class derived from CProdus.
Answer is: in Class CProdus the operator must be declared virtual, and in
CMagazin.cpp
void CMagazin::printExpirabile(const char *xdata)
{
list<CProdus*>::iterator it;
for (it = List_produse.begin(); it != List_produse.end(); ++it)
{
CProdus* p = *it;
if (p->get_tip()=='A')
{
if (p->operator>( xdata))-> make this!
{
p->print();
}
}
}
}
CProdus*p - is a pointer , need to have object for use this operator -> Try (*p)>xdata
void CMagazin::printExpirabile(const char *xdata)
{
list<CProdus*>::iterator it;
for (it = List_produse.begin(); it != List_produse.end(); ++it)
{
CProdus* p = *it;
if (p->get_tip()=='A')
{
if ((*p)>( xdata))-> make this!
{
p->print();
}
}
}
}

How to determine if a string can be manipulated to be rewritten as a palindrome?

I believe this can be achieved by counting the instances for each character in that string. Even if a single character in that string is repeated at least twice, we can declare that string as a palindrome.
For example: bbcccc can be rewritten as bccccb or ccbbcc.
edified can be rewritten as deified.
Some book mentioned we should be using hash table. I think we can just use a list and check for the character count.
Do you think the logic is correct?
Yes, the main idea is to count the times of each char existing in the string. And it will be true if the string has at most one char occurs odd times and all others even times.
For example:
aabbcc => acbbca
aabcc => acbca
aabbb => abbba
No. You don't have to use a hash map (as some of the other answers suggest). But the efficiency of the solution will be determined by the algorithm you use.
Here is a solution that only tracks odd characters. If we get 2 odds, we know it can't be a scrambled palindrome. I use an array to track the odd count. I reuse the array index 0 over and over until I find an odd. Then I use array index 1. If I find 2 odds, return false!
Solution without a hash map in javascript:
function isScrambledPalindrome(input) {
// TODO: Add error handling code.
var a = input.split("").sort();
var char, nextChar = "";
var charCount = [ 0 ];
var charIdx = 0;
for ( var i = 0; i < a.length; ++i) {
char = a[i];
nextChar = a[i + 1] || "";
charCount[charIdx]++;
if (char !== nextChar) {
if (charCount[charIdx] % 2 === 1) {
if (charCount.length > 1) {
// A scrambled palindrome can only have 1 odd char count.
return false;
}
charIdx = 1;
charCount.push(0);
} else if (charCount[charIdx] % 2 === 0) {
charCount[charIdx] = 0;
}
}
}
return true;
}
console.log("abc: " + isScrambledPalindrome("abc")); // false
console.log("aabbcd: " + isScrambledPalindrome("aabbcd")); // false
console.log("aabbb: " + isScrambledPalindrome("aabbb")); // true
console.log("a: " + isScrambledPalindrome("a")); // true
Using a hash map, I found a cool way to only track the odd character counts and still determine the answer.
Fun javascript hash map solution:
function isScrambledPalindrome( input ) {
var chars = {};
input.split("").forEach(function(char) {
if (chars[char]) {
delete chars[char]
} else {
chars[char] = "odd" }
});
return (Object.keys(chars).length <= 1);
}
isScrambledPalindrome("aba"); // true
isScrambledPalindrome("abba"); // true
isScrambledPalindrome("abca"); // false
Any string can be palindrome only if at most one character occur odd no. of times and all other characters must occur even number of times.
The following program can be used to check whether a palindrome can be string or not.
vector<int> vec(256,0); //Vector for all ASCII characters present.
for(int i=0;i<s.length();++i)
{
vec[s[i]-'a']++;
}
int odd_count=0,flag=0;
for(int i=0;i<vec.size();++i)
{
if(vec[i]%2!=0)
odd_count++;
if(odd_count>1)
{
flag=1;
cout<<"Can't be palindrome"<<endl;
break;
}
}
if(flag==0)
cout<<"Yes can be palindrome"<<endl;
My code check if can it is palindrome or can be manipulated to Palindrome
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
//Tested on windows 64 bit arhc by using cygwin64 and GCC
bool isPalindrome (char *text);
int main()
{
char text[100]; // it could be N with defining N
bool isPal,isPosPal = false;
printf("Give me a string to test if it is Anagram of Palindrome\n");
gets(text);
isPal = isPalindrome(text);
isPosPal = isAnagramOfPalindrome(text);
if(isPal == false)
{
printf("Not a palindrome.\n");
}
else
{
printf("Palindrome.\n");
}
if(isPosPal == false)
{
printf("Not Anagram of Palindrome\n");
}
else
{
printf("Anagram of Palindrome\n");
}
return 0;
}
bool isPalindrome (char *text) {
int begin, middle, end, length = 0;
length = getLength(text);
end = length - 1;
middle = length/2;
for (begin = 0; begin < middle; begin++)
{
if (text[begin] != text[end])
{
return false;
}
end--;
}
if (begin == middle)
return true;
}
int getLength (char *text) {
int length = 0;
while (text[length] != '\0')
length++;
printf("length: %d\n",length);
return length;
}
int isAnagramOfPalindrome (char *text) {
int length = getLength(text);
int i = 0,j=0;
bool arr[26] = {false};
int counter = 0;
//char string[100]="neveroddoreven";
int a;
for (i = 0; i < length; i++)
{
a = text[i];
a = a-97;
if(arr[a])
{
arr[a] = false;
}
else
{
arr[a] = true;
}
}
for(j = 0; j < 27 ; j++)
{
if (arr[a] == true)
{
counter++;
}
}
printf("counter: %d\n",counter);
if(counter > 1)
{
return false;
}
else if(counter == 1)
{
if(length % 2 == 0)
return false;
else
return true;
}
else if(counter == 0)
{
return true;
}
}
as others have posted, the idea is to have each character occur an even number of times for an even length string, and one character an odd number of times for an odd length string.
The reason the books suggest using a hash table is due to execution time. It is an O(1) operation to insert into / retrieve from a hash map. Yes a list can be used but the execution time will be slightly slower as the sorting of the list will be O(N log N) time.
Pseudo code for a list implementation would be:
sortedList = unsortedList.sort;
bool oddCharFound = false;
//if language does not permit nullable char then initialise
//current char to first element, initialise count to 1 and loop from i=1
currentChar = null;
currentCharCount = 0;
for (int i=0; i <= sortedList.Length; i++) //start from first element go one past end of list
{
if(i == sortedList.Length
|| sortedList[i] != currentChar)
{
if(currentCharCount % 2 = 1)
{
//check if breaks rule
if((sortedList.Length % 2 = 1 && oddCharFound)
|| oddCharFound)
{
return false;
}
else
{
oddCharFound = true;
}
}
if(i!= sortedList.Length)
{
currentCharCount = 1;
currentChar = sortedList[i];
}
}
else
{
currentCharCount++;
}
}
return true;
Here is a simple solution using an array; no sort needed
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a[256] = { 0 };
unsigned char i[] = {"aaBcBccc"};
unsigned char *p = &i[0];
int c = 0;
int j;
int flag = 0;
while (*p != 0)
{
a[*p]++;
p++;
}
for(j=0; j<256; j++)
{
if(a[j] & 1)
{
c++;
if(c > 1)
{
flag = 1;
break;
}
}
}
if(flag)
printf("Nope\n");
else
printf("yup\n");
return 0;
}
C#:
bool ok = s.GroupBy(c => c).Select(g => g.Count()).Where(c => c == 1).Count() < 2;
This solution, however, does use hashing.
Assuming all input characters are lower case letters.
#include<stdio.h>
int main(){
char *str;
char arr[27];
int j;
int a;
j = 0;
printf("Enter the string : ");
scanf("%s", str);
while (*str != '\0'){
a = *str;
a = a%27;
if(arr[a] == *str){
arr[a]=0;
j--;
}else{
arr[a] = *str;
j++;
}
*str++;
}
if(j==0 || j== -1 || j==1){
printf ("\nThe string can be a palindrome\n");
}
}