CompuServe Thread

#main(argc,argv)

17 messages in this thread
#35426From: Bart MathiasJun 19, 1993 2:42 AM
Two Major Questions (involving a bunch of minor puzzles). Finishing up a little program, almost ready to release it to the world. Just two relatively simple things to add: WorkBench startup capability and an ASL file requester for those running from OS 2.0+. Both simple things are proving formidable. For the WorkBench part, I linked with Astart.obj, which I got from the kind folks at Commodore. But the documentation says that, if the program was started from CLI, the number of command line arguments will be in argc and the arguments themselves in argv, passed as "main (argc,argv)," with "int argc;" and "char **argv;." But no mention of what all that means, such as where does one find this "argc" and "argv." Wherever they may be, I found an address register that points approximately to copies of the second (and later) CLI arguments, so I can run from the CLI. As for running the program from the WorkBench, I can do that too, in a way. Except that when I do an extended select I need a file name so I can Open() and Read() the file clicked on, but all the address in the sm_ArgList offset in the WBStartup structure points to is a bunch of strange numbers, e.g. (after shift-double-clicking on the tool icon and one project icon so there were two arguments) 000A17D5 002023FC 000A1803 … (middle one must be an address). So Major Question number 1 is, How do I convert sm_ArgList into something useful? I didn't have to read the fine manual much to get a general idea of how to put in an ASL file requester. But instead of popping up on my custom screen, it came out on the WorkBench screen. Read the fine manual some more. OK, I need a TagList to tell it what window. Spend a couple more hours to come up with a fairly clear–but apparently wrong–idea of how to manage a TagList, and the requester still comes out behind my screen on the WorkBench. Major Question number 2: What am I doing wrong? Here are the snippets of my code that seem relevant (most BEQs, BNEs, and LEAs deleted for brevity): [ MORE ]
#35431From: Steve GoddardJun 19, 1993 6:48 AM
Major Question 1: AS you have found out, the docs are biased towards C programmers. I don't use Astart.obj myself, but being a C programmer, can explain what the main() stuff means. AStart.obj fronts your program, and does some magic that sets up the overall environment (stack, etc), then formats the command line arguments, and calls your code. I think it does a jsr _main? When your code runs, it will have access to 2 variables, which will both be on the stack (although you may coincidentally find them in registers also). On the top of the stack will be a long integer, containing the number of CLI parameters typed. Typing the name of the program counts as 1, additional params are 2,3,.. etc. A program launched from WB will have 0 in here. The next long is an address. It is the addr of the following structure: addr –> Address1 Address2 Address3 0 The number of addresses pointed to varies, and there can be none (so addr would point to the 0) So dereferencing the Addr will give another address (Address1). Adding 4 and dereferencing will give Address2, etc until you find all zeroes. Each of these addresses points to a string of characters (terminated with a 0 byte). Each string is a single command line parameter, and the number of them is the same as the first param on the stack. Steve the G. [BEDFORDSHIRE, UK]
#35450From: Bart MathiasJun 20, 1993 3:31 AM
Thanks for the quick response. You UK people are really coming through for me on this one. With your information, I should have my CLI-started runs working the way they were intended; I was uneasy about using the copies of argument strings I found at A3 + 4, even though the results happened to be right. I spent a couple of hours reading RKM Libraries today, and noticed the (argc, **argv) rubric cropping up repeatedly. Do they always refer to the top longwords on the stack, I wonder. (And what do all those *'s mean, and what is the difference between UBYTE and (UBYTE) and BYTE, etc., etc. I guess I'm going to have to pick up a rudimentary knowledge of C somewhere.) Toiling over the RKM will probably pay off for my sm_ArgList problem too. I finally found out where it is discussed before I pooped out. Tomorrow… Thanks again. – via Whap!
#35488From: Brian BartlettJun 21, 1993 11:11 PM
Bart, I don't know enough to help you with the stack question, but I think I can help you with the rest. The (argc, *argv[]) construct is quite common in C. When a program is executed on most systems, the whole argument line from the CLI is passed to the executing program. Using a fairly simple routine, it is possible to parse the argument string and figure out what the user typed so that arguments are accepted. K&R (Kernighan & Ritchie) "The C Language," Second Edition, provides an adequate example of how to parse CLI arguments in pages 114-118. As you stated, a knowledge of the C language helps immensely with programming this beast. I did wonder as to your use of (argc, **argv). The first value is the number of arguments, including the first argument, i.e. the program name, that is passed to the called program. The second argument, *argv[], is an array of strings (characters) that can be indexed into to parse the strings. While **argv is "technically" correct, the more familiar usage is *argv[] (which is exactly the same thing as **argv). What does this mean to you? A bit of discussion is called for. In C, pointers are one of the more powerful tools available to the programmer. I'm sure, at this point, that you understand "what" a pointer is (i.e. an address of a data _value_), but I don't think you understand the syntax involved. In C, when you declare a pointer, you declare it in the following syntax: long *x; where x is the address of some long integer (i.e. 32 bit integer) you have somewhere, and *x is the value stored there. (Confused? I was! * in the declaration of a variable tells the compiler that you want to store an address, * in the usage of a variable means "I want the contents referred to by this address"). It is a given that you may already have the data _value_ stored somewhere, all you are doing here is telling the compiler to provide space to store the _pointer_ (i.e. address of) that _value_. Okay, now that you have the pointer, what do you do with it? Well, you can have it point to successive values stored in the system. If you have 20 long integers stored _succesively_, you can simply bump (increment) the pointer by one to point to the next value in memory. If, for instance, you had 3 long integers stored in memory, in successive memory locations, you could do an assignment picking off each of the successive values. Look at the following code fragment: long a[]={32, 64, 128}; /* Array of three elements 32, 64, 128 */ long *x=a; /* Assign pointer x to a[0]'s location */ printf("%l",*x); /* print first element */ printf("%l, *x+1); /* print second element */ printf("%l, *x+2); /* print third element */ As you will notice, bumping the pointer automagically skips, no matter what the element size, be it short, long, or even a complex record, to the next element, as it should, since we _are_ incrementing the "address of" some structural element's pointer. One of the curious, but nice, features of C is that array names behave like pointers, i.e., the first array element (element 0) is exactly the same address as a pointer of the same name. They are one and the same. So, when you see **argv, this is the same thing as *argv[0], which means, I've passed you a pointer to the first element of an array. You can bump this variable to point to the next element in the array. **argv+1 should give you the next string in the array of strings. So, if you, the user, had typed in a command line as follows: Whatzit abc def The programmer would see, passed to him, is an array of three strings with the following values: **argv = Whatzit **argv+1 = abc **argv+2 = def What is passed to you, the programmer, is a sequence of strings in an array. What you need to do is create a loop that, using argc (the ARGument Count) as the loop counter, grabs each of the strings and parses the meaning, or non-meaning, of each of the arguments. Each element will end in a C standard null byte, i.e. \0 = 0x00. The first argument *argv[0], or **argv, is, supposedly, the program name of your program. I hope this helps. Brian
#35595From: Bart MathiasJun 26, 1993 3:18 AM
Brian, I took a couple of days off to work on my bicycle, and came back to find a terrific C lesson from you. I'm hoping that by the time I digest what you explain about the use of "*" that I might get a handle on my remaining problem, which is having an ASL file requester open on the Workbench screen instead of my custom one. I've been wondering if there is something about request = AllocAslRequest( type, ptags ) struct TagItem *ptags (RKM: Includes & Autodocs, p16) that I don't understand that is causing the problem. Now I'll reconsider that in light of your explanation. What I've done so far is replace "ptags" with the address of my TagItem (namely ASL_Window,myWindow), but that doesn't work, so I'm obviously misunderstanding something. Maybe I'll buy K&R. I started looking at C textbooks at Walden Books yesterday. My use of **argv, by the way, was a direct quote from "Using Amiga Startups" in 2.0 Native Developer Update. Thanks again. Bart – via Whap!
#35602From: Michael McCormickJun 26, 1993 10:32 AM
Bart, I think this code fragment will help you with getting the ASL requster to open on your custom screen. struct TagItem loadtags[] = { ASLFR_TitleText, (ULONG)"Select Script File to Load", ASLFR_InitialHeight, fr_HEIGHT, ASLFR_InitialWidth, fr_WIDTH, ASLFR_InitialLeftEdge, fr_LEFTEDGE, ASLFR_InitialTopEdge, fr_TOPEDGE, ASLFR_InitialDrawer, (ULONG)"rexx:", ASLFR_InitialPattern, (ULONG)"#?.adpro", ASLFR_DoSaveMode, FALSE, ASLFR_Window, NULL, /* NOTE THIS LINE */ TAG_DONE, }; Then add this line in your program when calling the fr…. loadtags[8].ti_Data = (ULONG)MainWnd; /* Assign MainWnd to ASLFR_Window*/ Hope this helps…. MikeM:) "Amiga means never having to say you're sorry!"
#35611From: Bart MathiasJun 27, 1993 3:03 AM
Michael, Thanks, that may help, but I'll either have to figure out how to translate it to assembly language, or get a C compiler. Where you have /* NOTE THIS LINE */ is quite different from what I have done (though I use ALF_Window instead of ASLFR_Window, which I haven't been able to find in the RKM yet). That certainly suggests at least one more thing to try. Bart – via Whap!
#35616From: Michael McCormickJun 27, 1993 11:25 AM
Bart, I forgot to mention that is for 2.1 release of the OS. MikeM:) "Amiga means never having to say you're sorry!"
#35630From: Brian BartlettJun 28, 1993 12:51 AM
Bart, I'm happy to see that others can help you on the rest of this. You just went over my head <grin>. You really should check out the C Class files in the libs here, since they can probably give you enough to translate the C stuff to assembly. Good luck on your projects! Brian
#35687From: Bart MathiasJul 2, 1993 2:42 AM
Brian, Yes, I got the help I needed to eventually force me down the right track. But I very much appreciate your efforts to help, and I will take your advice to check out the C Class files. Bart – via Whap!
#35516From: Steve GoddardJun 23, 1993 2:44 PM
In standard C, ALL arguments are always passed on the stack. Every C compiler I have seen though, allows you to choose to pass params in registers, and some allow both stack AND registers to be used. Since the startup would be expected to be "standard" however, the stack is the place to look. Coincidentally, there *may* happen to be some leftovers in registers from when the startup fromend did its magic processing. The * is the neophyte C programmers nightmare. Its use is *very* context-dependent. When declaring a variable, it means address (such as would be stored in A1). In an expression where it does not mean multiplication, it dereferences an address (such as move.b (a3),d0. Double asterisks mean the address of an address. This only makes sense in assembly terms if you realise that an address is stored in memory like any other variable. UBYTE and BYTE are non-standard definitions that refer to 8bit quantities. The first is unsigned and the second signed. The only difference is subtleties such as sign extending when you convert them into 16 bit quantities, ASR vs LSR when shifting them right, etc. Brackets around a type (UBYTE) means that you are converting a variable to another type. So if you have a 16bit quantity (move.w d0,d1) and then use (UBYTE), the compiler will start generating move.b instructions. Steve the G. [BEDFORDSHIRE, UK]
#35596From: Bart MathiasJun 26, 1993 3:19 AM
Thanks for your note on C's *. I'm sure it will help. (But I'm also pretty sure I'm going to have to buy a C manual, even if just for the index.) With your help, and Shradhan's, I'm able to get my CLI and Workbench arguments in the approved manner. Now if I can just get my ASL file requester to open on the right screen… – via Whap!
#35601From: Steve GoddardJun 26, 1993 9:52 AM
I can't actually remember what the problem with ASL was. Was it something to do with putting reqs on the WB screen? From another message you mention AllocAslRequest. As you have mentioned, the taglist (2nd) parameter to this is a pointer to a list of tagitems. Remember that the list must end with TAG_DONE, 0. The ASLFR_Window tag allows you to specify which window the requester is attached to (and therefore which screen). There is also a tag called ASLFR_Screen, which specifies which screen to use. This overrides the window tag. The intuition function LockPubScreen will get you a screen pointer to the WB screen. Steve the G. [BEDFORDSHIRE, UK]
#35610From: Bart MathiasJun 27, 1993 3:03 AM
My other problem is getting a file requester to open on (the window in) my CUSTOMSCREEN. It opens behind my screen, on WorkBench, instead. I will try your suggestions, but I find no ASLFR_Window tag mentioned on a quick look in RKM. Only the ASL_Window that I have been using. And so far I haven't been able to find either an ASLFR_Screen or an ASL_Screen, but there is a WA_CustomScreen that is certainly worth a try. Meanwhile, just in case my problem is more fundamental, let me rehash what I have as of now. I open a custom screen 640X400 with NS_EXTENDED ored with CUSTOMSCREEN, and dc.l SA_Width,#-1 dc.l SA_Height,#-1 dc.l TAG_DONE tagged on at the end. I use OpenScreen() and OpenWindow() for 1.3 compatibility, and add tags to fix certain things that don't come out right otherwise in 2.04-2.1. I save the screen structure pointer in a memory location my assembler lets me call NSptr, which coincides with Screen in my NewWindow structure. Shortly thereafter I open the window, with WA_Borderless tagged TRUE (and followed by a TAG_DONE at the end). (This is where I'm thinking of trying to use WA_CustomScreen, though I'm not sure how.) I save the pointer at a random location named NWptr. In any event, my screen and window open just the way I want them to. Meanwhile (providing I got ver 36 or better of dos.library) I have opened the asl.library and save ASLbase. Then move.l ASL_FileRequest movea.l aslreqtag,a1 SYS AllocAslRequest([ASLbase]) [= jsr LVO_…] move.l d0,ASLfr and far below in my data storage: aslreqtag: dc.l ASL_Hail,frtit dc.l ASL_Window,NWptr dc.l TAG_DONE frtit: dc.b "JIStoJi File Requester",0 cnop 0,4 Apparently the "movea.l aslreqtag,a1" is not being understood, because when the user calls up a requester it comes out with the standard title on the WorkBench screen. – via Whap!
#35619From: Freddy PotargentJun 27, 1993 4:33 PM
Bart, Looking at your codefragment I believe I know the solution to your problem. First, the AllocAslRequest() function needs the address of the taglist so you should use 'lea aslreqtag,a1' instead of 'movea.l aslreqtag,a1'. The move instruction will put the contents at address 'aslreqtag' into a1 and you really need the address in a1 :-). The second problem is in the taglist itself. aslreqtag: dc.l ASL_Hail,frtit dc.l ASL_Window,NWptr <—– dc.l TAG_DONE frtit: dc.b "…title…",0 The problem is in the marked line, NWptr is some storage where the address of the OpenWindow() call is stored as I understand from your explanation. The above code will store the address of 'NWptr' into the taglist *not* the address of the windowstructure which should be put there. There are two solution: copy the contents of 'NWptr' to the correct position in the taglist or more neatly, place the NWptr storage directly into the taglist: aslreqtag: dc.l ASL_Hail,frtit dc.l ASL_Window NWptr: dc.l 0 dc.l TAG_DONE If you store the address of the windowstructure returned by OpenWindow() in NWptr it will be in the correct place. I tried both solutions and they work fine. Hope this solves your problem, Freddy. [On manual from Bilzen, Belgium]
#35686From: Bart MathiasJul 2, 1993 2:41 AM
Freddy, It was immediately obvious that changing move.l to lea as you suggested would help to solve my problem. I made that change and followed up with your suggestion to save my window structure pointer directly in the taglist. Then I compiled and ran, and the requester STILL came up on the WorkBench screen. So instead of working inside the big program I wrote a little one that does nothing but open a screen, and window, and an ASL requester, and started trying all kinds of things. They mostly didn't work until a few minutes ago. I don't think anyone would believe the number of errors of the kind you spotted I found in addition–I really wouldn't want anyone to. Suffice it to say that I found out I can read the manual over and over and over, and still not see what it says! I got it fixed. Thanks for speaking my language. Bart – via Whap!
#35433From: ShraddhanJun 19, 1993 7:01 AM
Bart, I've never used sm_ArgList. When your program gets started from the CLI, the operating system passes the number of arguments (argv ?) in D0 and a pointer to the CLI text in A0. I then just parse this text string. I didn't know there might be an easier way. (Is there, anybody?) As for using the ASL requester, I've always avoided it. I much prefer Khalid Aldoseri's requester; otherwise I'm using a WB1.3 machine and the old but simple ARP requester. Regards, Shraddhan (via AP at last from Hertfordshire, England)