Dan987

I got some old source code that uses _input(), but when I try to compile it, it says :
Error 1 error LNK2019: unresolved external symbol __input referenced in function _sscanf1

In source, it is:
int __cdecl _input (FILE *infile, const char *format, va_list arglist );

retval = (_input(infile,format,arglist));

I know this compiles in VC6, and 7, but it will not in VC 8 EE.

Can someone point me to how to fix this problem I can't even find any documentation on what _input is supposed to do.



Re: Visual C++ Express Edition Missing _input?

einaros

I can't find a single reference to _input in any of the header files shipped with my VS, nor the platform sdk. Is this part of some third party or custom library you're using

Other than that, I notice that the linker error complains about __input (two underscores, that is), while your declaration is using one underscore.






Re: Visual C++ Express Edition Missing _input?

Dan987


It *is* present in VC6 & 7, just not 8. This is why I am puzzled. The project files have the same .libs as each other, but it just can't find "_input()" anyplace in VC8 EE.

So they had to of changed it to something, but with no documentation on what _input() does exactly, I am in a bit of a quandary.


No, no special 3rd party lib or anything, just regular MS stuff.

The reason you see __input for linker, is because the linker adds a "_" to all functions.




Re: Visual C++ Express Edition Missing _input?

einaros

Dan987 wrote:

It *is* present in VC6 & 7, just not 8. This is why I am puzzled. The project files have the same .libs as each other, but it just can't find "_input()" anyplace in VC8 EE.

So they had to of changed it to something, but with no documentation on what _input() does exactly, I am in a bit of a quandary.

So what part of your code relies on this arcane construct I see that it's referenced from _sscanf1, but where exactly does that come into play Do you link another library which should be recompiled against a newer CRT


Dan987 wrote:

The reason you see __input for linker, is because the linker adds a "_" to all functions.

For functions with C linkage, thats true. I didn't see that specifier in the above code, but the lack of mangling should have tipped it off.






Re: Visual C++ Express Edition Missing _input?

Dan987

This is the C code snippet.

The only libs it uses is the normal ones in VC 6 & 7. Something in VC8 was changed, but nothing was mentioned that I can find, so I don't know what to link to now.

Code Snippet

int __cdecl _input (FILE *infile, const char *format, va_list arglist );

int __cdecl sscanf1 (char **stringPos,const char *format,...)

{

int retval;

char *string;

FILE str;

FILE *infile = &str;

va_list arglist;

string=*stringPos;

va_start(arglist, format);

infile->_cnt = 16384;

infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;

infile->_ptr = infile->_base = (char *) string;

retval = (_input(infile,format,arglist));

*stringPos=infile->_ptr;

return(retval);

}





Re: Visual C++ Express Edition Missing _input?

einaros

That whole blob can probably be rewritten using fscanf. Just move the FILE initialization out of "sscanf1", and replace the _input call with the parameters originally passed to to sscanf1 with a call to fscanf.




Re: Visual C++ Express Edition Missing _input?

nobugz

You were relying on an internal CRT implementation function, defined in input.c and used by scanf(), sscanf() and fscanf(). That function got renamed in the VC8 version of the CRT due to the safe CRT implementation. While you really ought to only use documented CRT functions, I think you're pretty stuck here. Try fixing it like this:

#ifdef __cplusplus
extern "C"
#endif
int __cdecl _input_l (FILE *infile, const char *format, _locale_t plocinfo, va_list arglist );

Pass a NULL for plocinfo. You'll have to statically link the CRT libraries, the symbol doesn't get exported in the DLL version. I got a clean compile but didn't test it.





Re: Visual C++ Express Edition Missing _input?

einaros

The way I see it, _input is (was) to fscanf as vsprintf is to sprintf. Rewriting it to use one of the actually present functions should bring you into the clear for generations to come.





Re: Visual C++ Express Edition Missing _input?

nobugz

What function would that be There is no vsscanf() afaik.





Re: Visual C++ Express Edition Missing _input?

einaros

No, there's no vsscanf, but all the sscanf1 above does is run a normal sscanf, then update the string pointer to point to whereever sscanf stopped reading.

Rewriting it using fscanf would go something like this:

Code Snippet

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <string.h>

typedef struct {
FILE f;
CRITICAL_SECTION lock;
} _FILEX;

#define sscanf1(streamPosition, ...) \
{ \
_FILEX sscanf1_file = {0}; \
InitializeCriticalSection(&sscanf1_file.lock); \
FILE* sscanf1_f = (FILE*)&sscanf1_file; \
char* sscanf1_str = *streamPosition; \
sscanf1_f->_flag = _IOREAD|_IOSTRG|_IOMYBUF; \
sscanf1_f->_ptr = (char*)sscanf1_str; \
sscanf1_f->_base = (char*)sscanf1_str; \
sscanf1_f->_bufsiz = strlen(sscanf1_str); \
sscanf1_f->_cnt = sscanf1_f->_bufsiz; \
fscanf((FILE*)&sscanf1_file, __VA_ARGS__); \
*streamPosition = sscanf1_f->_ptr; \
DeleteCriticalSection(&sscanf1_file.lock); \
}

int main()
{
char* str = "10 20";
int i;
sscanf1(&str, "%d", &i);
}






Re: Visual C++ Express Edition Missing _input?

nobugz

I think I see a couple of problems. The critical section would never lock, it is allocated on the stack. If you'd call EnterCriticalSection(), each thread would have a different pointer. Locking on a static instance isn't correct either, other threads would typically use different buffers. The CRT doesn't try to lock.

The streamPosition pointer would normally point to an uninitialized buffer, making strlen(sscanf1_str) invalid. The original code assumed a 16384 byte buffer, pretty much guaranteeing a lurking buffer overrun.





Re: Visual C++ Express Edition Missing _input?

einaros

nobugz wrote:
I think I see a couple of problems. The critical section would never lock, it is allocated on the stack. If you'd call EnterCriticalSection(), each thread would have a different pointer. Locking on a static instance isn't correct either, other threads would typically use different buffers. The CRT doesn't try to lock.

The critical section is merely there to satisfy requirements by fstream, as it expects a C_S to follow each FILE structure. The locking will happen within CRT, but it's pretty much unimportant. You should under no circumstances use the same string buffer on two threads simultaneously.

nobugz wrote:

The streamPosition pointer would normally point to an uninitialized buffer, making strlen(sscanf1_str) invalid. The original code assumed a 16384 byte buffer, pretty much guaranteeing a lurking buffer overrun.

No, the original code passes the source string as the first parameter to sscanf1. As the sscanf calls processes the string, the position will move ahead. In my example, the input would be "10 20" prior to the first run, then " 20" at the next. I presume the idea of sscanf1 is to iteratively go through a string, in a manner such as streams.






Re: Visual C++ Express Edition Missing _input?

nobugz

You are right, my compliments.





Re: Visual C++ Express Edition Missing _input?

Dan987

Thanks for that code snippet.

I tried it as is, and got errors (Error 3 error C2059: syntax error : ')' ) at the line

fscanf((FILE*)&sscanf1_file, __VA_ARGS__);

Looks like it don't like __VA_ARGS__ .

Will play around with it some more...

Thanks again.





Re: Visual C++ Express Edition Missing _input?

Dan987

nobugz wrote:
You were relying on an internal CRT implementation function, defined in input.c and used by scanf(), sscanf() and fscanf(). That function got renamed in the VC8 version of the CRT due to the safe CRT implementation. While you really ought to only use documented CRT functions, I think you're pretty stuck here. Try fixing it like this:

#ifdef __cplusplus
extern "C"
#endif
int __cdecl _input_l (FILE *infile, const char *format, _locale_t plocinfo, va_list arglist );

Pass a NULL for plocinfo. You'll have to statically link the CRT libraries, the symbol doesn't get exported in the DLL version. I got a clean compile but didn't test it.

You are correct, using _input_l() works. It is a bummer that you have to link statically though.

I was reading around, and it seems a function I should use, vfscanf () is missing in VC2005 EE edition, at least looking at this thread:

http://www.nabble.com/-Foxgui-users--Fox-1.6.19---MS-VC++-8.0,-don't-compile-t2630652.html

einaros, for your code snippet, I wouldn't be able to use the normal fscanf() like you have it, since it uses a va_list as final parameter, and I can't find a way for fscanf() to hanlde that.

Best option I guess would be to do as the above link says, and make your own function, now that I know what it does.

Thanks again, and if anyone has any other good ideas, I am all ears.