In a Visual FoxPro app using sockets, we are using wsock32.dll and use the htons() function to convert a portnumber to TCP/IP network byte order. It should return an unsigned short between 0 and 65535. When testing this with port 63333 it returns 26103 but after installing the Windows Fall Creators update it returns a bigger value: 16213495.
Sample FoxPro program:
DECLARE INTEGER htons IN "wsock32.dll" INTEGER hostshort
LOCAL portNumber, htonsNumber
portNumber = 63333
htonsNumber = htons( portNumber )
? htonsNumber
The resulting value should go into a "sockaddr" structure used by the connect() function but there is only space for 2 bytes for the port.
Does anyone know what has happened in this windows update to the wsock32 functions and/or has a suggestion to solve this?
I compared the Windows 10 FCU function with Windows 8 and Windows has reordered the register usage and saved one AND instruction. This is most likely a compiler optimization and not a source code change. Because the left-shifted half is not masked you get garbage in bits 16-23 but these bits should be ignored. The function is still correct for anyone that follows the Windows ABI.
The best solution is to update the function declaration so it uses a 16-bit integer type. If that is not possible you can cast the number to a 16-bit type in languages that support casting. The final option is to truncate the value yourself by ANDing with 0xffff:
htonsNumber = BitAnd(htons(portNumber), 0xffff)
SHORT is listed as a valid return type so that should work as well:
DECLARE SHORT htons IN "wsock32.dll" INTEGER
Related
I have an unformatted binary file generated using the Compaq Visual Fortran compiler (big endian).
Here's what the little bit of documentation states about it:
The binary file is written in a general format consisting of data arrays, headed by a descriptor record:
An 8-character keyword which identifies the data in the block.
A 4-byte signed integer defining the number of elements in the block.
A 4-character keyword defining the type of data. (INTE, REAL, LOGI, DOUB, or CHAR)
The header items are read in as a single record. The data follows the descriptor on a new record. Numerical arrays are divided into block of up to 1000 items. The physical record size is the same as the block size.
Attempts to read such data
module modbin
type rectype
character(len=8)::key
integer::data_count
character(len=4)::data_type
logical::is_int
integer, allocatable:: idata(:)
real(kind=8), allocatable::rdata(:)
end type
contains
subroutine rec_read(in_file, out_rec)
integer, intent(in):: in_file
type (rectype), intent(inout):: out_rec
!
! You need to play around with this figure. It may not be
! entirely accurate - 1000 seems to work, 1024 does not
integer, parameter:: bsize = 1000
integer:: bb, ii, iimax
! read the header
out_rec%data_count = 0
out_rec%data_type = ' '
read(in_file, end = 20) out_rec%key, out_rec%data_count,
out_rec%data_type
! what type is it?
select case (out_rec%data_type)
case ('INTE')
out_rec%is_int = .true.
allocate(out_rec%idata(out_rec%data_count))
case ('DOUB')
out_rec%is_int = .false.
allocate(out_rec%rdata(out_rec%data_count))
end select
! read the data in blocks of bsize
bb = 1
do while (bb .lt. out_rec%data_count)
iimax = bb + bsize - 1
if (iimax .gt. out_rec%data_count) iimax = out_rec%data_count
if (out_rec%is_int) then
read(in_file) (out_rec%idata(ii), ii = bb, iimax)
else
read(in_file) (out_rec%rdata(ii), ii = bb, iimax)
end if
bb = iimax + 1
end do
20 continue
end subroutine rec_read
subroutine rec_print(in_recnum, in_rec)
integer, intent(in):: in_recnum
type (rectype), intent(in):: in_rec
print *, in_recnum, in_rec%key, in_rec%data_count, in_rec%data_type
! print out data
open(unit=12, file='reader.data' , status='old')
write(12,*)key
!write(*,'(i5')GEOMINDX
!write(*,'(i5')ID_BEG
!write(*,'(i5')ID_END
!write(*,'(i5')ID_CELL
!write(*,'(i5')TIME_BEG
!write(*,'(i5')SWAT
!format('i5')
!end do
close(12)
end subroutine rec_print
end module modbin
program main
use modbin
integer, parameter:: infile=11
! fixed size for now - should really be allocatable
integer, parameter:: rrmax = 500
type (rectype):: rec(rrmax)
integer:: rr, rlast
open(unit=infile, file='TEST1603.SLN0001', form='UNFORMATTED',
status='OLD', convert='BIG_ENDIAN')
rlast = 0
do rr = 1, rrmax
call rec_read(infile, rec(rr))
if (rec(rr)%data_type .eq. ' ') exit
rlast = rr
call rec_print(rr, rec(rr))
end do
close(infile)
end program main
This code compiles and runs smoothly showing
and produces no errors but this is written in the output file
shows me no useful numerical values
The file in question is available here
And the right WRITE statement should produce a file like this one here
Is my WRITE STATEMENT to output this file type wrong? , and if so, what is the best way?
thank you
The comments above are trying to direct you to one of (at least) two problems in your code. In the subroutine rec_print you have write(12,*)key where you meant to write write(12,*)in_rec%key (at least I think that's what you wanted.)
The other problem I spotted is that rec_print opens reader.data with status='old' and then closes it after writing key. (The use of old here suggests that the file already exists.) Each time rec_print is called, the file is opened, the first record is overwritten, and the file is closed. One solution to this would be to use status='unknown'. position='append', though it would be more efficient to open the file once in the main program and just let the subroutine write to it.
If I make these changes, I get in the data file:
INTEHEAD
GEOMETRY
GEOMINDX
ID_BEG
ID_END
ID_CELL
TIME_BEG
SWAT
A side-comment about CONVERT= and derived types: Your program isn't affected by this, but there are compiler differences with how reading a derived type record with CONVERT= is handled. I think gfortran converts each component according to its type, but I know that Intel Fortran doesn't convert reads (nor writes) of an entire derived type. You are reading individual components, which works in both compilers, so that's fine, but I thought it was worth mentioning.
If you're wondering why Intel Fortran does it this way, it's due to the VAX FORTRAN (where CONVERT= came from) heritage with STRUCTURE/RECORD and the possible use of UNION/MAP (not available in standard Fortran). With unions, there's no way to know how a particular component should be converted, so it just transfers the bytes. I had suggested to the Intel team that this could be relaxed if no UNIONs were present, but that I'm sure is very low priority.
How do you use SQLBindParameter to write an array of strings to a VARCHAR field in DB2 in a memory-efficient way?
The example in the DB2 docs does this
SQLCHAR Description[NUM_PRODS][257] = {
"Aquarium-Glass-25 litres", "Aquarium-Glass-50 litres",
"Aquarium-Acrylic-25 litres", "Aquarium-Acrylic-50 litres",
"Aquarium-Stand-Small", "Aquarium-Stand-Large",
"Pump-Basic-25 litre", "Pump-Basic-50 litre",
"Pump-Deluxe-25 litre", "Pump-Deluxe-50 litre",
"Pump-Filter-(for Basic Pump)",
"Pump-Filter-(for Deluxe Pump)",
"Aquarium-Kit-Small", "Aquarium-Kit-Large",
"Gravel-Colored", "Fish-Food-Deluxe-Bulk",
"Plastic-Tubing"
};
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 257, 0, Description, 257, NULL);
I can get that to work without issues but it isn't very efficient since each string is stored using 256 characters(+null-terminator) regardless of its actual length. More generally, if you had one very long string (say 500 chars) and every other string was one character, you would still need a two-dimensional array of size [NUM_STRINGS][500] which wastes a lot of memory.
What I would like to do is pass SQLBindParameter an array that looks like
SQLCHAR* Description[NUM_STRINGS];
where each element of the array points to a string. This would be more memory-efficient since each string only uses the space it needs but I can't figure out how to get it to work using SQLBindParameter. Any help would be appreciated.
NOTE: General answers for any DB would be great but answers that are specific to DB2 would also be helpful.
The sizes I am working with involve millions of strings with widely varying lengths so being memory-efficient is a significant factor.
I am actually using DB2 on Linux, but for this specific usecase, the only example I could find was in the DB2 for z/OS docs. It does work correctly though except for the memory usage issue.
The SQL Insert statement below is used to insert unicode string and it is working successfully when executed in SQL Server Management Studio or Query Analyzer.
Column Specs:
SONUM VARCHAR(50)
CONTRACTNUM NVARCHAR(150)
FNAME VARCHAR(70)
INSERT INTO SCH_EDI_3B12RHDR ( SONUM, CONTRACTNUM, FNAME )
VALUES ( 'DPH11309160073CC' , N'Globe MUX Project(客户合同号:NA)' , 'TEST' )
Is it possible to implement the prefix N when using a datastore/datawindow for insert operation? If yes, how? Below is the current script in PB which successfully insert the data but the chinese character/s was replaced by '?'(question mark).
ls_sonum = String(dw_1.Object.shipmentOrderNum[1]) //This holds the value : DPH11309160073CC
ls_chinesechar = String(dw_1.Object.contractnum[1]) // This holds the value : Globe MUX Project(客户合同号:NA)
dw_1.SetItem(1,'sonum',ls_sonum)
dw_1.SetItem(1,'contractnum',ls_chinesechar)
dw_1.SetItem(1,'fname','TEST')
dw.AcceptText( )
IF dw.Update( ) = 1 THEN
Commit Using SQLCA ;
END IF
You need to hook yourself on the sqlpreview event of dw/ds and add the N' yourself. Or if you use static (or disable?) bind you don't need to do anything at all.
It's all explained in the online docs.
I verified that the OLE DB driver for PB version 10 supports Unicode. You can find the information in this Sybase document on page nine.
ODBC/ JDBC /OLEDB/ ADO.NET DATABASE SUPPORT
Client/Server PowerBuilder 10 applications can exchange Unicode and ANSI data with databases
supported by the ODBC, JDBC, OleDB, and ADO.NET database interfaces without requiring
special settings.
Suggestion would be to try forcing a different encoding when using the string function, there are four choices (see code example below)
The encoding parameter is one of the following:
■ EncodingANSI!
■ Encoding UTF8!
■ EncodingUTF16LE! – UTF-16 Little Endian encoding (PowerBuilder 10 default)
■ EncodingUTF16BE! – UTF-16 Big Endian encoding
// use the correct encoding for your actual data
ls_sonum = String(dw_1.Object.shipmentOrderNum[1], EncodingUTF16BE! ) //holds DPH11309160073CC
ls_chinesechar = String(dw_1.Object.contractnum[1], EncodingANSI!) // holds Globe MUX Project(客户合同号:NA)
It is possible that I'm leading you down the wrong path but I think this would be worth trying out and may solve the problem.
I am currently having issues when trying to store a 16bit number coming from the input of my module into one of my logic variables. When I set all the bits high in my test bench I get a value: 0000000000000001. Hope you can help! PS: Sorry, dont know how to insert code on here....
My code is shown below:
http://pastebin.com/cZCYKJqV
I think your problem is likely with this line:
regy = (!regy)+1;
regy is a 16-bit value. Using the negation operator (!) on a multi-bit value is equivalent to (value != 0). So for any value of regy other than zero will set regy to 1.
If you are trying to invert all the bits and add 1, you need to use the ~ operator.
Example:
regy = (~regy)+1;
I have a C SDK I need to use in an iPhone project, and the example code was written for use with Visual Studio. It includes use of strcpy_s, which is a Microsoft-only string function.
file_header.header_size = FIT_FILE_HDR_SIZE;
strcpy_s((FIT_UINT8 *)&file_header.data_type, sizeof(".FIT"), ".FIT"); << problem!
I've tried changing to strcpy and strncpy like so
strncpy((FIT_UINT8 *)&file_header.data_type, ".FIT", sizeof(".FIT"));
But I get this warning:
warning: pointer targets in passing argument 1 of 'builtin_strncpy_chk' differ in signedness
warning: pointer targets in passing argument 1 of '__inline_strncpy_chk' differ in signedness
warning: call to builtin_strncpy_chk will always overflow destination buffer
The struct file_header is this:
typedef struct
{
FIT_UINT8 header_size; // FIT_FILE_HDR_SIZE (size of this structure)
FIT_UINT8 protocol_version; // FIT_PROTOCOL_VERSION
FIT_UINT16 profile_version; // FIT_PROFILE_VERSION
FIT_UINT32 data_size; // Does not include file header or crc. Little endian format.
FIT_UINT8 data_type[4]; // ".FIT"
} FIT_FILE_HDR;
FIT_UINT8 is typedef Unsigned char.
So we can see that it is given an length of 4 in the typedef, and the strcpy_s takes the data_type by reference and copys ".FIT" to it. Where am I going wrong with strncpy? If you haven't guessed by now I'm not much of a C programmer :)
Edit: this does not give me an error, but it is correct?
strncpy((void *)&file_header.data_type, ".FIT", sizeof(file_header.data_type));
With any "safe string" operations, the size should almost always be the size of the destination buffer; if you use the size of the source string, you might as well call memcpy.
If you want C99 conformance:
strncpy(file_header.data_type, ".FIT", sizeof file_header.data_type);
However, strlcpy (a BSDism, available in iOS) is preferred by many, because it guarantees that the destination will be nul-terminated:
strlcpy(file_header.data_type, ".FIT", sizeof file_header.data_type);
Note, however that the nul-terminated string ".FIT" doesn't actually fit in the allotted space, as it requires 5 characters (1 for the trailing nul). If you use strlcpy, you will see that the resulting string is just ".FI" because strlcpy guarantees nul-termination, and truncates your string if necessary.
If you require nul-termination then, you probably want to increase the size of the data_type array to 5. As caf correctly points out, this looks like a file header, in which case nul-termination is probably not required; in that case strncpy is preferred; I might even use memcpy, and avoid giving a future developer the idea that the field is a string.
Don't use
sizeof(".FIT")
use
strlen(".FIT")