View Full Version : Pipes, Standard Input and x86 ASM under DOS/WIN issue
sedarious
10-24-2002, 05:31 PM
Okay, here is the basic setup. I have an app that takes input from either a pipe or the command line. It will default to command line if its there. Otherwise, it goes to the pipe. I am using the 0x3F function to read the data from stdin (where the pipe data is). My problem is that 0x3F will PROMPT for user input if there is nothing in stdin. I would prefer if it would simply output an error message instead of waiting for input.
Now heres there problem. I am not sure how to deal with checking the stdin for data. I tried the 0x44 subfunctions as well as 0x0B. Neither of these seem to work correctly with a pipe. I realize that i could rewrite the 0x3F function to not grab user input (or many other variations on re-writing interrupts), but I am curious if there is some other way to do this. Either by having a proper check for data or using a function besides 0x3F for getting the stdin data. Here is the part of code that is important...
org 0x100
section .data USE32
errormessage db 'usage: tobin <string> or use pipe','$'
section .text USE32
_start:
cmp byte [0x80],0
ja commandline
stdin:
;-------------
;check for data here somehow
;-------------
mov ax,0x3f00
mov bx,0
mov cx,0x200
mov dx,buffer
int 0x21
cmp ax,0
je term
mov word [length],ax
jmp init
commandline:
xor ch,ch
mov cl,[0x80]
mov word [length],cx
mov si,0x81
mov ax,buffer
mov di,ax
mov bx,ds
mov es,bx
repnz movsb
init:
;do some stuff
jmp term
error:
mov ah,0x09
mov dx,errormessage
int 0x21
term:
mov ah,0x4c
int 0x21
jemfinch
10-24-2002, 06:13 PM
Wouldn't it just be easier to check if the command line has data, and if not, read stdin? That's the standard way of doing it in C, and would seem to accomplish your, "use the command line before stdin" requirement in one fell swoop.
Jeremy
sedarious
10-24-2002, 06:17 PM
Originally posted by jemfinch
Wouldn't it just be easier to check if the command line has data, and if not, read stdin? That's the standard way of doing it in C, and would seem to accomplish your, "use the command line before stdin" requirement in one fell swoop.
Jeremy
Actually, thats exactly what I am doing. It checks the command line. If nothing is there, it will go to stdin. The problem is that if there isn't any data is stdin, then it will WAIT for input (grabs all keys until a CR). That is what I am trying to avoid - the input. Its not really a bad thing so much, its just not how I want it to work...
jemfinch
10-25-2002, 01:23 AM
Well, that is standard *nix behavior -- if no files are given, take input on stdin. Try, for instance, "cat" with no arguments on the command line -- it just sits there waiting on input on stdin. I don't think you really have anything to fix.
Jeremy
jemfinch
10-25-2002, 01:24 AM
I'm not an assembly programmer, obviously, but in C, you should just be able to pop that file descriptor into non-blocking mode, do a read, and if the read returns 0, then there's nothing to be read, and you could exit with an error message.
Jeremy
stuka
10-25-2002, 12:00 PM
int 16h, ah=1 will set the zero flag if there is no data available from the keyboard - you could use that as a check before your DOS call.
sedarious
10-25-2002, 04:46 PM
stdin:
mov ax,0x4200
mov bx,0
mov cx,[fp]
mov dx,[fp+2]
int 0x21
mov word [fp],dx
mov word [fp+2],ax
mov ax,0x4202
mov bx,0
mov cx,[fp2]
mov dx,[fp2+2]
int 0x21
mov word [fp2],dx
mov word [fp2+2],ax
mov eax,[fp]
mov ebx,[fp2]
cmp ebx,eax
je error
mov ax,0x4200
mov bx,0
mov cx,0
mov dx,0
int 0x21
mov ax,0x3f00
mov bx,0
mov cx,0x200
mov dx,buffer
int 0x21
mov word [length],ax
jmp init
I actually solved this at about 10 this morning and I thought I had posted such - guess not. This is what it now looks like. I am grabbing the pointer to the beginning and end of the file and checking them for equivalence. If they are equal, then there is nothing in the buffer. I have a thread going in ArsForum and hardforum (nothing much at [H] forum on it though).
I understand that what I am trying to work around is actually standard procedure - I just don't like how it works. It doesn't seem very graceful to me, thats all. Someone at ars mentioned that the OS might not schedule the apps in the right order meaning that in the case of prog1 | prog2, program1 might run AFTER program two (at least thats what i got from what he said). Since program2 (the prog I am working on) won't be waiting for program1 to finish, I could have a problem. Anyway, thats whats up. Any thoughts or suggestions are still welcome.
stuka
10-25-2002, 05:00 PM
Well, I don't know how to apply this in assembly, but the proper way to do this in C, on Unix platforms, is (within the second program) to close() stdin (assuming the input is coming from the first application), and dup() the file descriptor that the first program is outputting on. I have NO idea how this would work on a DOS platform.
jemfinch
10-25-2002, 05:08 PM
The guy from Ars is right, and you probably shouldn't "fix" that standard behavior for just that reason.
Jeremy
sedarious
10-25-2002, 05:16 PM
Ideally, I should be checking in program 2 to see if program 1 has finished execution and THEN check stdin to see if anything is there. I am not quite so sure how to go about that though.
edit: Just saw your post jeremy. I agreed that this wasn't the proper way to go about it. I just don't like how it just hangs on no input... (well, waits would be a better word)
bwkaz
10-26-2002, 09:48 AM
The other thing is, I'm fairly sure that in *nix anyway, there aren't any buffers to hold piped data.
Which means that whenever program1 does a write, it gets blocked until program2 reads in that data -- assuming you've set them up in a pipeline, like you were saying: program1 | program2.
Which also means you can't wait for program1 to finish before trying to read the data in, because if you try, you'll run into a deadlock really fast. program1 will be waiting for program2 to read the other end of the pipe, and program2 will be waiting for program1 to exit -- classic deadlock.
Although if pure DOS is single-tasking, then it would simply have to save the data written to the pipe somewhere, because it won't let the other process even run, let alone read from the pipe... which means it has to have an internal buffer somewhere... which means if you were to write out (say) 500 megs of data from program1, you'd easily overflow that buffer... remember, DOS is limited to 640K. Or am I not thinking straight?
Of course, all this flies right out the window if you're using an NT kernel. There is no pure DOS, and I wouldn't be surprised if the programs in the pipeline did actually execute as separate tasks. But I don't know for sure...
sedarious
10-26-2002, 11:28 AM
No, you are right. DOS can only allocate 640K at a time via its internal memory allocation function. I am just going to have it wait for stdin. This is mearly a test to see if there was some way to gracefully handle it - which it doesn't look like there is. In the case of and stdin hang (where prog2 is waiting for data that isn't coming in say a hourly script), I supose I could just run an external prog to check for hangs or build in a "timeout" ability (if specified from command line) to leave and return an error if it is running more than 10 minutes or something.
vBulletin® v3.7.0, Copyright ©2000-2009, Jelsoft Enterprises Ltd.