/*
//
// ADOBE SYSTEMS INCORPORATED
// Copyright (C) 2000-2003 Adobe Systems Incorporated
// All rights reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file
// in accordance with the terms of the Adobe license agreement
// accompanying it. If you have received this file from a source other
// than Adobe, then your use, modification, or distribution of it
// requires the prior written permission of Adobe.
//
*/
// MTSerialNums.cpp : Defines the entry point for the console application.
// This application demonstrates how to use the multi-threaded version of
// PDFL. Each thread opens a base document and adds a serial number to it
// to create a serialized version of the base document.
//
#include "MyPDFLibUtils.h"
#include "SDKThreads.h"
#include "Watermark.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
typedef struct ThreadArgs {
int id;
const char *filename;
const char *outdir;
const char *basename;
} ThreadArgs;
// A CSMutex is the local (within this process only) semaphore for
// protecting a critical section of code that modifies an important
// data object shared among threads (or with exception handlers)
CSMutex serialNumberCS;
// serialNumber is the counter shared among the threads.
// maxSerialNumber is the limit of work to be performed.
static volatile int serialNumber;
static int maxSerialNumber;
// getSerialNumber is the "get work" function. Here we just
// return an int, but the key here is the technique. Several threads
// could be wanting work at the same time.
int getSerialNumber()
{
int retval = -1;
// Here's the key crtical section. Only 1 thread at a time in here...
EnterCS( serialNumberCS );
// Is there any more work to do? There are really 3 answers to
// this question, but only 2 are represented here. Here we test
// for the "no, never" case. If there will never be more work,
// return a -1, which is a signal to the caller that we're done.
// If there is more work, we return the serial number to use.
// The third case is "no, not now, but maybe later". For that case,
// we should either wait for a signal or an appropriate amount of
// time to check again, being careful not to hog the critical
// section. But this is a simple sample...
if (serialNumber != -1) {
// Get the next bit of work to do.
retval = serialNumber++;
// For this example, we run out of work when we run out of serial
// numbers. So test for that and set the flag for all the other
// callers of this function.
if (retval > maxSerialNumber)
retval = serialNumber = -1;
}
// Done modifying serialNumber, leave the critical section.
LeaveCS( serialNumberCS );
// and return the serial number to generate.
return retval;
}
// This is the thread worker function.
ThreadFuncReturnType threadFunc( ThreadArgs *pArgs )
{
INIT_AUTO_POOL(autoReleasePool); /* Required only on MAC platform */
int serialNumber, err;
char *ofn;
char watermark[100];
ASSize_t buffLen = strlen( pArgs->outdir ) + strlen( pArgs->basename ) + 20;
ofn = ( char *)malloc( sizeof ( char ) * buffLen);
if (ofn ==
NULL) return 0;
// A loop that does work until there's no more work to do.
while ((serialNumber = getSerialNumber()) != -1) {
// Do the work itself. Here we just print the serial number...
printf( "Thread %d got serial number %d\n" , pArgs->id, serialNumber );
err = MyPDFLInit(); // Initialize the PDFLibrary
if (err != 0) {
fprintf(stderr, "Initialization error. See \"AcroErr.h\" for more info.\n" );
fprintf(stderr, "Error system: %d\nError Severity: %d\nError Code: %d\n" ,
ErrGetSystem(err),
ErrGetSeverity(err),
ErrGetCode(err));
free( ofn );
return 0;
}
sprintf_safe( ofn, buffLen, "%s/%s%06d.pdf" , pArgs->outdir, pArgs->basename, serialNumber );
sprintf_safe( watermark, sizeof (watermark), "Copy Serial Number %06d" , serialNumber );
Serialize( pArgs->filename, ofn, watermark );
MyPDFLTerm();
}
free( ofn );
RELEASE_AUTO_POOL(autoReleasePool); /* Required only on MAC platform */
return 0;
}
int main( int argc, char * argv[])
{
INIT_AUTO_POOL(autoReleasePool); /* Required only on MAC platform */
int numThreads = 3; // Default number of threads
int i;
FILE *fp;
ThreadInfo *threads;
ThreadArgs *threadArgs;
{ // Deal with command line argument processing...
// Print out some usage info if we don't get it right...
// Could have pre-programmed some defaults instead, of course.
if (6 > argc || argc > 7) {
printf( "Usage: %s InputDocument OutputDirectory OutputFileBaseName StartingSerialNumber NumberOfCopies [NumberOfThreads]\n" , argv[0] );
printf( "Use absolute paths for InputDocument and OutputDirectory.\n" );
return 0;
}
// Validate the input file name argument
if ((fp = fopen(argv[1], "r" )) ==
NULL) {
printf( "Cannot open input document \"%s\"\n" , argv[1] );
return 0;
}
else
fclose( fp );
serialNumber = atoi( argv[4] ); // Starting serial number
maxSerialNumber = atoi( argv[5] ) + serialNumber -1; // Maximum serial number
if (maxSerialNumber < serialNumber || serialNumber < 0) {
printf( "Serial numbers have to be positive and max must be greater than starting.\n" );
return 0;
}
// Get the number of threads
if (argc == 7)
numThreads = atoi( argv[6] ); // Number of threads to use
if (numThreads <= 0) {
printf( "NumberOfThreads must be 1 or more\n" );
return 0;
}
// Validate the output directory argument
// Because this may be destructive (if a file with the target name already
// exists) we do this last, using the first file name.
ASSize_t buffLen = strlen( argv[2] ) + strlen( argv[3] ) + 20;
char *fn = ( char *)malloc( sizeof ( char ) * buffLen );
sprintf_safe( fn, buffLen, "%s/%s%06d.pdf" , argv[2], argv[3], serialNumber );
if ((fp = fopen( fn, "w" )) ==
NULL) {
printf( "Cannot create file in output directory \"%s\"\n" , argv[2] );
free( fn );
return 0;
}
fclose( fp );
remove ( fn );
free( fn );
} // End of command line argument processing
// Initialize the PDF Library
int err = MyPDFLInit();
if (err != 0) {
fprintf(stderr, "Initialization error. See \"AcroErr.h\" for more info.\n" );
fprintf(stderr, "Error system: %d\nError Severity: %d\nError Code: %d\n" ,
ErrGetSystem(err),
ErrGetSeverity(err),
ErrGetCode(err));
return 0;
}
InitCS( serialNumberCS ); // Initialize the CSMutex
// Allocate a ThreadInfo object for each thread
threads = (ThreadInfo *)malloc( sizeof ( ThreadInfo ) * numThreads );
// Allocate a ThreadArgs object for each thread
threadArgs = (ThreadArgs *)malloc( sizeof ( ThreadArgs ) * numThreads );
// Start the threads, passing their thread number to each
for (i = 0; i < numThreads; i++) {
threadArgs[i].id = i;
threadArgs[i].filename = argv[1];
threadArgs[i].outdir = argv[2];
threadArgs[i].basename = argv[3];
if (!createThread( threadFunc, &threadArgs[i], threads[i] ))
printf( "Thread creation %d failed\n" , i );
}
// Clean up the threads, after waiting for each to exit.
for (i = 0; i < numThreads; i++) {
waitThread( threads[i] );
destroyThread( threads[i] );
}
// Free up threadInfo and threadArgs
free( threads );
free( threadArgs );
// Now destroy the CSMutex
DestroyCS( serialNumberCS );
// Shut down the PDF Library
MyPDFLTerm();
RELEASE_AUTO_POOL(autoReleasePool); /* Required only on MAC platform */
// Exit
return 0;
}