Output text file

2

Comments

  • Thanks for the suggestions gautam.
    I shall try to integrate them into the C++ version.
    At the moment I am trying to make it a non-console app.

    Regards

    TT

  • : Thanks for the info Eric.
    : I am using DJGPP/RHIDE/WIN98 and it had some problems with your new header:
    : >int WinMain (HINSTANCE hInstance, HINSTANCE, hPrevInstance,
    : >LPSTR cmdline, int show)
    : >{
    : >int& argc = __argc;
    : >char**& argv = __argv;
    :
    : After lots of trying I found this in the DJGPP manual:
    : "Q: Can I write MS-Windows applications with DJGPP?
    : A: Currently, you can only run DJGPP programs under Windows as DOS apps (i.e. inside the DOS Box). If you need to write true Windows apps, you will have to use auxiliary tools or another compiler."
    : So it looks like DJGPP cannot do it, unless DOS can be run as a non-console app, which would be really useful, but I do not think it can.

    Oh, yeah, well DJGPP is a DOS compiler, so of course you cannot write Windows apps. Just download Borland's 5.5 compiler. It's a free, fast, 32-bit Windows compiler that happens to be one of the most ANSI compliant compilers on the market.

  • Just download Borland's 5.5 compiler but it refused to do anything with your new code.
    Can you see a problem with how I have added the new header?

    TT

    -----------------writetext.c-----------------------------------
    #include
    #include
    int WinMain (HINSTANCE hInstance, HINSTANCE, hPrevInstance, LPSTR cmdline, int show)
    {

    int& argc = __argc;
    char**& argv = __argv;

    #define FILENAME "writetext.txt"
    FILE *FileStream; // Make a stream pointer.
    int nCount;
    char *sString;

    // For fopen (Filename, Mode):
    // Mode "w" means: Overwrite old if it exists, or make a new one if
    // it doesn't.
    // Mode "a" means append to end of file.
    if( (FileStream = fopen (FILENAME, "w")) == NULL)
    {
    // printf () replace whatever is at the %n (where n is a type
    // character) with the value after the quoted area.
    // It is really useful for formatting output as you want it.
    printf ("Error, could not open up file %s", FILENAME);
    return 0;
    }

    // Account for variable amounts of parameters by depending on the argc
    // value. The first parameter starts at 1, not zero.
    for (nCount = 1; nCount < argc; nCount++)
    {
    // We use sString as a character pointer to point to the beginning
    // of the string we want to output so we don't need to copy the
    // value to a temporary variable which also saves memory.
    // The pointer is the most powerful construct in C/C++. It is the
    // "hallmark" feature which allows the code to point a pointer
    // to any location in memory instead of passing a copy of that value.
    sString = argv[nCount];
    fprintf (FileStream, "Parameter #%i: %s
    ", nCount, sString);
    }
    fclose (FileStream); // Close stream after we're done.

    return 0;
    }

    C:WINDOWSDesktoporl>bcc32 writetext.c
    Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
    writetext.c:
    Error E2147 writetext.c 3: 'HINSTANCE' cannot start a parameter declaration
    Error E2303 writetext.c 3: Type name expected
    *** 2 errors in Compile ***


  • : Just download Borland's 5.5 compiler but it refused to do anything with your new code.
    : Can you see a problem with how I have added the new header?

    You need to include .

    You also need to tell BCC to create a non-console app by using the -tW (target=Windows) option.

    : int WinMain (HINSTANCE hInstance, HINSTANCE, hPrevInstance, LPSTR cmdline, int show)
    There's also a typo in the above function declaration (the comma after HINSTANCE). Also, WinMain gets called by Windows, so it must use the "standard" calling convention (rather than the regular C calling convention). You can specify the calling convention in Borland with the '__stdcall' keyword. Also, Borland's compiler will give you warnings that hInstance, hPrevInstance, cmdline and show are never used. As you should [italic]never[/italic] ignore compiler warnings, we will fix that. All three of the above mention changes will get you here:

    [code]int __stdcall WinMain (HINSTANCE, HINSTANCE, LPSTR, int)[/code]So to build correctly:
    1) replace the WinMain line in your program with the one above
    2) #include somewhere above WinMain
    3) use the -tW switch on the compiler command line

    Cheers,
    Eric





  • : : [code]
    :
    : This is C -:). I was merely doing it in c++ , but I have some queries on this - isn't it better to use
    : FILE *FileStream;
    : FileStream = fopen(FILENAME,"w");
    :
    : if (!FileStream)
    : {
    : /* output an error message*/
    : }
    : /* do the rest */
    :

    [/code]


    Throwing it into an if statement does the exact same thing and with less lines. Plus it unifies the entire statement into one block.

    -Xotor-

  • : : So it looks like DJGPP cannot do it, unless DOS can be run as a non-console app, which would be really useful, but I do not think it can.
    :
    : Oh, yeah, well DJGPP is a DOS compiler, so of course you cannot write Windows apps. Just download Borland's 5.5 compiler. It's a free, fast, 32-bit Windows compiler that happens to be one of the most ANSI compliant compilers on the market.

    Timmytoadie: Unless you're going to take advantage of compiling Windows apps, don't bother using a Windows compiler (unless of course you like the IDE). You're making console apps, and quite frankly it is a lot easier to start programming on a DOS compiler than using a Windows compiler and trying to make it work with Windows. Most universities will not use Windows compilers either, though my high school did (though never did any Windows programming).

    -Xotor-

  • Just be glad they never made you use Code Warrior. It has the worst IDE I have ever seen, not to mention use it on a Macintosh is painful.

    If a school has to pick an alternative OS (i.e. not Windows), I'd much rather learn to use a *nix or full DOS machine...

  • Hey Xotor,Thanks for your help before.
    DJGPP was/is preferred by me.
    But I want to write a non-console Windows app
    (ie no dos screen flashing up when it runs)
    and it seems this is difficult or not possible using DJGPP
    and (hopefully) possible/less difficult using Borland.
    The free Borland 5.5 compiler I just downloaded does not seem to
    have an IDE like RHIDE that I used in DJGPP so I am using EditPlus
    until I can get EMACS to do it.
    The idea is at some point to have a C or C++ exe that can be called
    from a Flash 5 projector and output text reports via an FSCommand sending
    filename and report text as parameters (like Ftooltext or afsaver only
    more configurable).

    Regards

    TT

  • : Timmytoadie: Unless you're going to take advantage of compiling Windows apps, don't bother using a Windows compiler (unless of course you like the IDE).

    Why? Windows has like 90% of the desktop PC market. How could it possibly hurt to use a Windows compiler? It seems to me there are only benefits.

    : You're making console apps, and quite frankly it is a lot easier to start programming on a DOS compiler than using a Windows compiler and trying to make it work with Windows.

    How is it easier? Even if it was marginally easier (and I'm not agreeing that it is), it would be worth the extra effort to use a Windows compiler. DOS has been obsolete for years. Perhaps it's still used for some embedded applications, and for students and hobbyist, but it's real world relevance is limited. Why not learn to program on a modern OS, so that when you're ready to stretch out and learn network programming or multithreading program or programming - your OS will support it.

    > Most universities will not use Windows compilers either, though my high school did (though never did any Windows programming).

    Mine does. They provide both NT and UNIX machines - two modern OSes. If you go to a University that is still running DOS on it's computers, I would be worried.

    Cheers,
    Eric

  • : I have some queries on this - isn't it better to use
    : FILE *FileStream;
    : FileStream = fopen(FILENAME,"w");
    :
    : if (!FileStream)
    : {
    : /* output an error message*/
    : }

    I would definitely agree that:

    [code] File* FileStream = fopen(FILENAME,"w");
    if (FileStream == NULL)
    {
    handle error
    }[/code]is better style than:[code] File* FileStream;
    if( (FileStream = fopen (FILENAME, "w")) == NULL)
    {
    handle error
    }[/code]The both do exactly the same thing, and generate exactly the same machine code, but the first is simpler.

    Another stylistic improvement (IMHO) is to test for success, rather than failure. The main line of execution should be the positive case, when everything works. Below that should be the error handling cases. Like this:

    [code]if (successful operation)
    {
    do something
    do something else
    if (another succesful operation)
    {
    do some more stuff
    yet another thing to do
    }
    else
    {
    handle error
    }
    else
    {
    handle error
    }[/code]This allows you to easily follow the 'normal' path of execution in a linear fashion, and the error handling is localized below it. I picked this up from "Code Complete" by Steve McConnell (which every programmer should own).

    Cheers,
    Eric



  • : Thanks for the post & code Xotor.
    : I compiled it and found it worked pretty much the same as mine (although your exe is a lot smaller).
    : 2 problems remain with both sets of code.
    : 1) When this exe is called by another program it flashes up briefly on the screen. It would be preferable if this did not happen, but I do not know how to stop it.

    If you want to see the output of the program you can:

    (In RHIDE) press Alt-F5 and you'll see the output.

    Or use a pause statement at the end of your program:

    [code]
    int Pause ()
    {
    printf ("Press any key to continue");
    return fgetc (stdin);

    }
    [/code]


    : 2) How to get a whole string output as one param rather than just one word variables?
    : ie. if command line param1 = "This is a Report"
    : Hope the above makes sense, it is what I am working on right now.

    No, it doesn't support that, but you can make a function to parse it into a single string. The problem is that you have to make sure that the string is long enough for all the parameters.

    Here's a parser, you pass it the number of arguments (nArgV), a pointer to the sArgC parameter, and the string you want to store it in (sOutput). Make sure sOutput is long enough:

    [code]

    int ParseParameters (int nArgV, char **sArgC, char *sOutput)
    {
    int i;

    for (i = 1; i < nArgV; i++)
    {
    strcat (sOutput, sArgC[i]);
    strcat (sOutput, " ");
    }
    if (strlen(sOutput) > 0) sOutput[strlen (sOutput) - 1] = 0;

    return 0;
    }

    [/code]



    : PS I like #define FILENAME idea.
    : I made one slight amend to your code so that the name of the
    : text file is set by command line param1 (see below).

    I'd actually suggest you stick it at the top. Most people put them at the top so they can be modified very easily without having to search the code. Remember that any command with a # before it is a compiler directive, not part of the code itself. #define merely replaces instances of the word it defines verbatim.

    -Xotor-

  • : : Timmytoadie: Unless you're going to take advantage of compiling Windows apps, don't bother using a Windows compiler (unless of course you like the IDE).
    :
    : Why? Windows has like 90% of the desktop PC market. How could it possibly hurt to use a Windows compiler? It seems to me there are only benefits.

    You're misunderstanding the situation Eric. He is learning how to program C/C++, not learning how to program a Windows app. You do not learn the alphabet by picking up a dictionary, and you do not learn how to program by building a full fledged Windows app.

    Making apps for Windows is hardly an ideal way for people to start programming. In fact it will probably scare them.

    : : You're making console apps, and quite frankly it is a lot easier to start programming on a DOS compiler than using a Windows compiler and trying to make it work with Windows.
    :
    : How is it easier? Even if it was marginally easier (and I'm not agreeing that it is), it would be worth the extra effort to use a Windows compiler. DOS has been obsolete for years. Perhaps it's still used for some embedded applications, and for students and hobbyist, but it's real world relevance is limited. Why not learn to program on a modern OS, so that when you're ready to stretch out and learn network programming or multithreading program or programming - your OS will support it.

    Read my paragraph above. *START PROGRAMMING* is the key work. Most people are not weaned on Windows programming. It's like saying a baby should learn how to run before he can walk because he can get to places faster. You don't learn by starting at the top and working down.

    Maybe when he has a solid foundation of C/C++ he should move onto Windows programming, but not when he still hasn't even worked with pointers.

    : > Most universities will not use Windows compilers either, though my high school did (though never did any Windows programming).
    :
    : Mine does. They provide both NT and UNIX machines - two modern OSes. If you go to a University that is still running DOS on it's computers, I would be worried.

    From the shear volume of people who visit this board asking for Turbo C++ I would guess that Turbo C++ is still quite a bit in use. Why? Because is it simple to use, it provides an easy interface to show students how to output their results to the screen, and it is probably as basic as you can get.

    And again, I'm not speaking of advanced programming which could make use of a Windows compiler. I'm talking about people starting out in programming.

    -Xotor-

  • This board really sucks... only ten messages per thread reply? Just lame..

    : [code] File* FileStream = fopen(FILENAME,"w");
    : if (FileStream == NULL)
    : {
    : handle error
    : }[/code]is better style than:[code] File* FileStream;
    : if( (FileStream = fopen (FILENAME, "w")) == NULL)
    : {
    : handle error
    : }[/code]The both do exactly the same thing, and generate exactly the same machine code, but the first is simpler.

    But is it though? The latter method attaches the error handling code directly to the action which could cause the error. The action is thereby unified as one statement, taking advantage of the variable's return code and does not require two actions like the first.

    : Another stylistic improvement (IMHO) is to test for success, rather than failure. The main line of execution should be the positive case, when everything works. Below that should be the error handling cases. Like this:
    :
    : [code]if (successful operation)
    : {
    : do something
    : do something else
    : if (another succesful operation)
    : {
    : do some more stuff
    : yet another thing to do
    : }
    : else
    : {
    : handle error
    : }
    : else
    : {
    : handle error
    : }[/code]This allows you to easily follow the 'normal' path of execution in a linear fashion, and the error handling is localized below it. I picked this up from "Code Complete" by Steve McConnell (which every programmer should own).

    That's really cute, but what if you have multiple successful operations, one after another? Do you continue to nest over and over again? It would look like this:

    [code]
    if (success)
    {
    // Do something.
    if (success)
    {
    // Do something.
    if (success)
    {
    // Do something.
    if (success)
    {
    // Do something.
    if (success)
    {
    // Do something.
    } else {
    // Error handle
    }
    } else {
    // Error handle
    }
    } else {
    // Error handle
    }
    } else {
    // Error handle
    }
    } else {
    // Error handle
    }
    [/code]


    Surely you can see that you're going to run off the screen after a while. I really hate looking at programs which are so far tabbed because of nested if statements that I need to scroll to the right to view the code, or set my tab spacing to two or so.

    If you simply test for failure and move on, you spare yourself the endless trees of if statements. The problem is dealt with once, and the program moves on. Additionally, it eliminates the extra else statement.

    -Xotor-


  • Thanks Eric,

    The modified code below compiles in Borland.
    It does now run as a non-console windows app with no flashing
    dos box when called from the Flash projector and outputs the text file as expected. I also made the "Mode" of fopen accessible via a command line parameter.
    I am working on the "output" aspect of it at the moment.
    Maybe I will get Flash to output with pipes for spaces
    and have writetext.exe convert pipes back to spaces.
    (Flash: "This|is|a|report" -> writetext: "This is a report").
    Basically Flash will have to output variables of different
    lengths mixed with some hard coded strings.
    (Flash: "The name is :" + userName);

    Regards

    TT


    -------------------writetext.cpp------------------------------
    #include
    #include
    #include

    int __stdcall WinMain (HINSTANCE, HINSTANCE, LPSTR, int)
    //int WinMain (HINSTANCE hInstance, HINSTANCE, hPrevInstance, LPSTR cmdline, int show)
    {

    int& argc = __argc;
    char**& argv = __argv;
    #define FILENAME argv[1]
    FILE *FileStream; // Make a stream pointer.
    int nCount;
    char *sString;

    // For fopen (Filename, Mode):
    // Mode "w" means: Overwrite old if it exists, or make a new one if
    // it doesn't.
    // Mode "a" means append to end of file.
    if( (FileStream = fopen (FILENAME,argv[2])) == NULL)//Mode set by param 2
    {
    // printf () replace whatever is at the %n (where n is a type
    // character) with the value after the quoted area.
    // It is really useful for formatting output as you want it.
    printf ("Error, could not open up file %s", FILENAME);
    return 0;
    }

    // Account for variable amounts of parameters by depending on the argc
    // value. The first parameter starts at 1, not zero.
    for (nCount = 1; nCount < argc; nCount++)
    {
    // We use sString as a character pointer to point to the beginning
    // of the string we want to output so we don't need to copy the
    // value to a temporary variable which also saves memory.
    // The pointer is the most powerful construct in C/C++. It is the
    // "hallmark" feature which allows the code to point a pointer
    // to any location in memory instead of passing a copy of that value.
    sString = argv[nCount];
    fprintf (FileStream, "Parameter #%i: %s
    ", nCount, sString);
    }
    fclose (FileStream); // Close stream after we're done.

    return 0;
    }


    -------------------writetext.cpp------------------------------



  • : : }[/code]The both do exactly the same thing, and generate exactly the same machine code, but the first is simpler.
    :
    : But is it though? The latter method attaches the error handling code directly to the action which could cause the error.

    Not really, it just squishes two operations onto one line. Fewer lines does not mean better code, just fewer lines.

    : The action is thereby unified as one statement, taking advantage of the variable's return code and does not require two actions like the first.

    Again, it still requires two actions. First the function is called and it's return value is stored in the variable FileStream, second the value in FileStream is compared with NULL and we branch accordingly. The compiler is going to generate the exact same code regardless of whether you compact it all into one line or not. It's just a matter of which one is more readable. You could argue that the second form is plenty readable to an experienced C programmer, it's a very common idiom after all. However, it's just a better habit to strive for the absolute maximum clarity possible. If the expression was more complicated, say another test needed to be added, it just increases the chance of error and makes the code harder to read. Also, less experienced programmers might have to look at it a couple time to figure it out, and less experienced programmers are the ones who get stuck maintaining code in many production environments. There's really no upside to doing this way. It gains you nothing. But there are numerous downsides. This is just my opinion of course. If you want others options check out Code Complete by Steve McConnell or Writing Solid Code by Steve Maguire, two excellent books that most of the professional programmers I know own.

    : : Another stylistic improvement (IMHO) is to test for success, rather than failure. The main line of execution should be the positive case, when everything works.
    : That's really cute, but what if you have multiple successful operations, one after another? Do you continue to nest over and over again? It would look like this:

    : Surely you can see that you're going to run off the screen after a while. I really hate looking at programs which are so far tabbed because of nested if statements that I need to scroll to the right to view the code, or set my tab spacing to two or so.

    What's more important, writing clear maintainable code that can be easily understood by others, or writing code that is esthetically pleasing in shape but is more difficult to follow?

    Here's an example form Code Complete (Pascal):

    [code][b]Processing errors haphazardly[/b]

    OpenFile( Input File, Status )
    if Status = Error then
    error case --- ErrorType = FileOpenError
    else
    nominal case - ReadFile( InputFile, FileData, Status )
    if Status = Success then
    nomical case - SummarizeFileData( FileDta, SummaryData, Status )
    if Status = Error then
    error case --- ErrorType = DataSummaryError
    else
    nominal case - PrintSummary( SummaryData )
    SaveSummaryData( SummaryData, Status )
    if Status = Error then
    error case --- ErrorType = SummarySaveError
    else
    nominal case - UpdateAllAccounts
    EraseUndoFile
    ErrorType = None
    end if
    end if
    else
    error case --- ErrorType = FileReadError
    end if
    end if


    [b]Processing errors systematically[/b]

    OpenFile( Input File, Status )
    if Status <> Error then
    nominal case - ReadFile( InputFile, FileData, Status )
    if Status = Success then
    nominal case - SummarizeFileData( FileDta, SummaryData, Status )
    if Status <> Error then
    nominal case - PrintSummary( SummaryData )
    SaveSummaryData( SummaryData, Status )
    if Status <> Error then
    nominal case - UpdateAllAccounts
    EraseUndoFile
    ErrorType = None
    else
    error case --- ErrorType = SumarySaveError
    end if
    else
    error case --- ErrorType = DataSummaryError
    end if
    else
    error case --- ErrorType = FileReadError
    end if
    else
    error case --- ErrorTYpe = FileOpenError
    end if[/code]The second method allows a programmer unfamiliar with the code (or even you yourself reading your own code months after you wrote it) to follow the code in a linear fashion. You don't have to jump around to different sections of the code to find the 'nominal' path of execution.

    : If you simply test for failure and move on, you spare yourself the endless trees of if statements. The problem is dealt with once, and the program moves on. Additionally, it eliminates the extra else statement.

    True, and I'm not saying that I don't do this myself from time to time, but I consider it a bad habit. Even when I do it myself. ;) In the strict structured programming world, programs are supposed to have a single entry point and a single exit point. No early returns, because they make it too easy for maintenance errors to occur. This assertion [italic]is[/italic] backed up by empirical studies at IBM and other companies. Does that stop us vain programmers from using early returns to avoid unsightly nesting? No. But it's still no reason to recommend it to beginners as a Good Practice.

    Regards,
    Eric




Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories