LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I get 'PrintTextFile ()' to recognize form feeds

I have a text file with embedded form-feed chars, what does it take to get those characters to perform their specified function in PrintTextFile ()? Little square boxes instead of a real page-feed is not satisfactory!
0 Kudos
Message 1 of 12
(4,696 Views)
An interesting question. As far as I know, this cannot be done in a direct fashion, but it should be able to fake it out with a little finesse. By making use of the ATTR_EJECT_AFTER print attribute, we can simulate a form feed by using multiple calls to PrintTextBuffer. All that remains is to read the file and search out the form feed characters and remove them and then print the intervening text with ATTR_EJECT_AFTER turned on. I haven't tested this but it seems like it should work. Here is the code I hammered out for this:


void PrintTextFileWithFFChar (const char filename[], char outputFile[], char ffChar)
{
int oldEject, done = 0, size;
char buffer[1025] = { 0 }, *ptr, *ffLoc;
FILE *file;

if ((file = fopen (filename, "rb")) == NULL)
return;


GetPrintAttribute (ATTR_EJECT_AFTER, &oldEject);
SetPrintAttribute (ATTR_EJECT_AFTER, 0);

while (!done && (size = fread (buffer, 1, sizeof(buffer) - 1, file)) > 0)
{
ptr = buffer;

buffer[size] = '\0';

SetPrintAttribute (ATTR_EJECT_AFTER, 1);
while ((ffLoc = strchr (ptr, ffChar)) != NULL)
{
*ffLoc = '\0';
PrintTextBuffer (ptr, outputFile);
ptr = ffLoc + 1;
}

if (feof (file))
{
SetPrintAttribute (ATTR_EJECT_AFTER, oldEject);
done = 1;
}
else
SetPrintAttribute (ATTR_EJECT_AFTER, 0);

PrintTextBuffer (ptr, outputFile);
}

fclose(file);
}

You invoke it as usual, but specifying the character that is used to indicate a form feed (12 in ASCII, I belive).

Like so:

PrintTextFileWithFFChar ("file.txt", "", 12);


Hope this helps...

Regards,

-alex
0 Kudos
Message 2 of 12
(4,695 Views)
This is the way I am currently doing it and the output looks fine, the only problem is that the output must go to a network printer and each call to 'PrintTextBuffer ()' produces a print job (i.e. each page is a seperate print job). I am also running in a multi-threaded environment, i.e. there are four threads doing the same thing. When the threads do printouts, it creates a mess with all of the interleaving (since each page is a seperate print job) and requires manual sorting of the pages. Currently the printout has 23 pages, but the final version will most likely have as much as 200 pages. Can you see the mess.

I cannot believe that NI has been so shortsighted as to disallow the normal page formatting in text files that has been available for decades.
0 Kudos
Message 3 of 12
(4,695 Views)
Indeed, it seems messy. I suppose (assuming the files are of managable size) you could make the buffer large enough to read the entire file into memory (ie. get the size of the file and allocate a buffer of that size + 1). In that case, the only page breaks would correspond to the form feeds. This would also make the code for the print wrapper simpler.

WRT multithreading, you could protect calls to the print wrapper with a mutex (you could even do this internally in the function so it would be transparent to client code). Hopefully the function runtime would be fast enough that this would not impose too much blocking of the other threads.

I agree that this is not an ideal solution but I think it should be functional and it may be the best you can
do for now.

Best of luck,

-alex
0 Kudos
Message 4 of 12
(4,695 Views)
I extended my example to include the ideas I mentioned. I don't know if it will be satisfactory but it might be worth a try.

Regards,

-alex


#include
#include
#include
#include "toolbox.h"

int PrintTextFileWithFFChar (const char filename[], char outputFile[], char ffChar);

static int gPrintLock = 0;

int main(void)
{
CmtNewLock ("PrintLock", OPT_TL_PROCESS_EVENTS_WHILE_WAITING, &gPrintLock);

PrintTextFileWithFFChar ("print.txt", "", 12);

CmtDiscardLock (gPrintLock);

return 0;
}

int PrintTextFileWithFFChar (const char filename[], char outputFile[], char ffChar)
{
int error = UIENoError, oldEject, done = 0, size;
long fileSize = 0, totalRead = 0;
char *buffer, *ptr, *ffLo
c;
FILE *file;

CmtGetLock (gPrintLock);

errChk (GetFileSize (filename, &fileSize));

nullChk (file = fopen (filename, "rb"));

nullChk (buffer = calloc (fileSize + 1, 1));

errChk (GetPrintAttribute (ATTR_EJECT_AFTER, &oldEject));
errChk (SetPrintAttribute (ATTR_EJECT_AFTER, 0));

while (!feof (file) && totalRead < fileSize)
{
int read = fread (buffer + totalRead, 1, fileSize - totalRead, file);
if (read < 0)
break;
totalRead += read;
}

ptr = buffer;

errChk (SetPrintAttribute (ATTR_EJECT_AFTER, 1));
while ((ffLoc = strchr (ptr, ffChar)) != NULL)
{
*ffLoc = '\0';
errChk (PrintTextBuffer (ptr, outputFile));
ptr = ffLoc + 1;
}

errChk (SetPrintAttribute (ATTR_EJECT_AFTER, oldEject));

errChk (PrintTextBuffer (ptr, outputFile));

fclose (file);
free (buffer);
Error:
CmtReleaseLock (gPrintLock);

return error;
}
0 Kudos
Message 5 of 12
(4,695 Views)
Another part of the application is responsible for creating the file with all of the embedded form-feeds (about 4K per page). Reading it into one big buffer solves nothing since the form-feeds will not print unless a 'PrintTextBuffer ()' is done for each page. The printing part of the application sets other print attributes (e.g. orientation, font ...) in order to make the document more easily readable.

I still have the problem with other network print jobs getting interleaved.
0 Kudos
Message 6 of 12
(4,695 Views)
Tiny bug: free(buffer) and fclose(file) should both be below the Error tag and should both check their respective parameters for NULL. Also, buffer and file should be initialized to NULL at the top.
0 Kudos
Message 7 of 12
(4,695 Views)
I have tried a variation of your latest code. In my variation I was able to get page feeds out of the printer without having to use the ATTR_EJECT_AFTER. When I tried using the outputfile with each PrintTextBuffer call and then one final call to actually print the outputfile by calling PrintTextFile (outputfile, ""); (which is missing in your code) the output starts out like this (only 2 lines shown):

%112345@PJL JOB NAME="Untitled"
@PJL COMMENT "8150 Series (PCL 5e)Version 4.2.1.0 Dev. Vers"

There are a number lines with Printer Control Language, then what looks like binary data followed by more PCL. There is nothing resembling the contents of the original report whatsoever. All of this is compressed into 6 pages.
0 Kudos
Message 8 of 12
(4,695 Views)
I'll go ahead and attach the test program I made up; give it a try and let me know if you have problems (it works fine for me with CVI 7.1).

I included the test .txt file (with two embedded form feeds) which is otherwise a few snippets from these forums chosen at random.

Regards,

-alex
0 Kudos
Message 9 of 12
(4,695 Views)
Ok, I've included my function inline:

======================================================
#define PAGE_BUF_SIZE 0x3000

void PrintReport (char *path)
{

char inBuf[MAX_PATHNAME_LEN];
char pageBuf[PAGE_BUF_SIZE] = {'\0'};
int oldEject;
int pageIndex = 0;
int prevWaitCursorState = GetWaitCursorState ();
FILE *report;

if (NULL == path)
return;

if ('\0' == path[0])
return;

if (NULL == (report = fopen (path, "r")))
return;

SetWaitCursor (1);

GetPrintAttribute (ATTR_EJECT_AFTER, &oldEject);

CmtNewLock ("PrintLock", OPT_TL_PROCESS_EVENTS_WHILE_WAITING, &sPrintLock);

// Set printing attributes
SetPrintAttribute (ATTR_ORIENTATION, VAL_LANDSCAPE);
SetPrintAttribute (ATTR_PRINT_FONT_NAME, VAL_SYSTEM_META_FONT);
SetPrintAttribute (ATTR_PRINT_POINT_SIZE, 14);
SetPrintAttribute (ATTR_TAB_INTERVAL, 8);
SetPrintAttribute (ATTR_TEXT_WRAP, FALSE);

// All pages have form-feeds
SetPrintAttribute (ATTR_EJECT_AFTER, 1);

// Print the file
for (;;)
{

int len, flag = 0;
char *outBuf = inBuf;

fgets (inBuf, MAX_PATHNAME_LEN - 1, report);
if (feof (report))
break;

// Check for form-feed or page buffer full
if ('\f' == inBuf[0])
{
outBuf++;
if (pageIndex)
flag++;
}

len = strlen (outBuf);

// The page buffer has filled up (should never happen), print it
if ((pageIndex + len) > (PAGE_BUF_SIZE - 1))
{
flag++;
}

if (flag)
{
// Output the text buffer now
PrintTextBuffer (pageBuf, "");

pageIndex = 0;
pageBuf[0] = '\0';
}

// Copy input line into page buffer
strcpy (&pageBuf[pageIndex], outBuf);
pageIndex += len;

}

SetPrintAttribute (ATTR_EJECT_AFTER, oldEject);

// Output partial buffer
if (pageIndex)
PrintTextBuffer (pageBuf, "");

fclose (report);

CmtReleaseLock (sPrintLock);

SetWaitCursor (prevWaitCursorState);
}

=======================================================

The only thing I've added was the 'ATTR_EJECT_AFTER' calls, which made absolutely no difference. I still see one print job queued on the network print queue per page. The ONLY way to get rid of this problem is for 'PrintTextFile ()' to honor form-feed characters, I need ALL of the output to be in ONE print-job! This function is a workaround to the REAL problem. It only solves HALF the problem.
0 Kudos
Message 10 of 12
(4,694 Views)