示例#1
0
int gs_band_donor_init(void        **opaque,
                       gs_memory_t  *mem)
{
#ifdef DEBUG_PRINT
    emprintf(mem, "gs_band_donor_init\n");
#endif
    *opaque = NULL;
    return 0;
}
示例#2
0
FILE *
gp_open_scratch_file (const gs_memory_t *mem,
                      const char        *prefix,
                      char               fname[gp_file_name_sizeof],
                      const char        *mode)
{
    char thefname[256];
    Str255 thepfname;
    OSErr myErr;
    short foundVRefNum;
    long foundDirID;
    FSSpec fSpec;
    FILE *f;
    int prefix_length = strlen(prefix);

    if (prefix_length > gp_file_name_sizeof) return NULL;
    strcpy (fname, (char *) prefix);
      {
        char newName[50];

        tmpnam (newName);
        if ( prefix_length + strlen(newName) > gp_file_name_sizeof ) return NULL;
        strcat (fname, newName);
      }

   if ( strlen(fname) > 255 ) return NULL;
   if ( strrchr(fname,':') == NULL ) {
       memmove((char*)&thepfname[1],(char *)&fname[0],strlen(fname));
           thepfname[0]=strlen(fname);
                myErr = FindFolder(kOnSystemDisk,kTemporaryFolderType,kCreateFolder,
                        &foundVRefNum, &foundDirID);
                if ( myErr != noErr ) {
                        emprintf(mem, "Can't find temp folder.\n");
                        return (NULL);
                }
                FSMakeFSSpec(foundVRefNum, foundDirID,thepfname, &fSpec);
                convertSpecToPath(&fSpec, thefname, sizeof(thefname) - 1);
                sprintf(fname,"%s",thefname);
   } else {
       sprintf((char*)&thefname[0],"%s\0",fname);
       memmove((char*)&thepfname[1],(char *)&thefname[0],strlen(thefname));
           thepfname[0]=strlen(thefname);
   }

    f = gp_fopen (thefname, mode);
    if (f == NULL)
        emprintf1(mem, "**** Could not open temporary file %s\n", fname);
    return f;
}
示例#3
0
void
gx_san__release(gx_device_spot_analyzer **ppadev)
{
    gx_device_spot_analyzer *padev = *ppadev;

    if (padev == NULL) {
        /* Can't use emprintf here! */
	eprintf("Extra call to gx_san__release.");
	return;
    }
    if(--padev->lock < 0) {
	emprintf(padev->memory, "Wrong lock to gx_san__release.");
	return;
    }
    if (padev->lock == 0) {
	*ppadev = NULL;
	rc_decrement(padev, "gx_san__release");
    }
}
示例#4
0
static int
os2_printer_fopen(gx_io_device * iodev, const char *fname, const char *access,
                  FILE ** pfile, char *rfname, uint rnamelen)
{
    os2_printer_t *pr = (os2_printer_t *)iodev->state;
    char driver_name[256];

    /* Make sure that printer exists. */
    if (pm_find_queue(pr->memory, fname, driver_name)) {
        /* error, list valid queue names */
        emprintf(pr->memory, "Invalid queue name.  Use one of:\n");
        pm_find_queue(pr->memory, NULL, NULL);
        return_error(gs_error_undefinedfilename);
    }

    strncpy(pr->queue, fname, sizeof(pr->queue)-1);

    /* Create a temporary file */
    *pfile = gp_open_scratch_file(pr->memory, "gs", pr->filename, access);
    if (*pfile == NULL)
        return_error(gs_fopen_errno_to_code(errno));

    return 0;
}
示例#5
0
/* Set up and start the render threads */
static int
clist_setup_render_threads(gx_device *dev, int y, gx_process_page_options_t *options)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_memory_t *chunk_base_mem = mem->thread_safe_memory;
    gs_memory_status_t mem_status;
    int i, band;
    int code = 0;
    int band_count = cdev->nbands;
    int band_height = crdev->page_info.band_params.BandHeight;
    crdev->num_render_threads = pdev->num_render_threads_requested;

    if(gs_debug[':'] != 0)
        dmprintf1(mem, "%% %d rendering threads requested.\n", pdev->num_render_threads_requested);

    if (crdev->num_render_threads > band_count)
        crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */

    /* Allocate and initialize an array of thread control structures */
    crdev->render_threads = (clist_render_thread_control_t *)
              gs_alloc_byte_array(mem, crdev->num_render_threads,
              sizeof(clist_render_thread_control_t), "clist_setup_render_threads" );
    /* fallback to non-threaded if allocation fails */
    if (crdev->render_threads == NULL) {
        emprintf(mem, " VMerror prevented threads from starting.\n");
        return_error(gs_error_VMerror);
    }

    memset(crdev->render_threads, 0, crdev->num_render_threads *
            sizeof(clist_render_thread_control_t));
    crdev->main_thread_data = cdev->data;               /* save data area */
    /* Based on the line number requested, decide the order of band rendering */
    /* Almost all devices go in increasing line order (except the bmp* devices ) */
    crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1;
    band = y / band_height;

    /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */
    gs_memory_status(chunk_base_mem, &mem_status);
    if (mem_status.is_thread_safe == false) {
            return_error(gs_error_VMerror);
    }

    /* If we don't have one large enough already, create an icc cache list */
    if (crdev->num_render_threads > crdev->icc_cache_list_len) {
        void *old = crdev->icc_cache_list;
        crdev->icc_cache_list = gs_alloc_byte_array(mem->thread_safe_memory,
                                    crdev->num_render_threads,
                                    sizeof(void*), "clist_render_setup_threads");
        if (crdev->icc_cache_list == NULL) {
            crdev->icc_cache_list = NULL;
            return_error(gs_error_VMerror);
        }
        if (crdev->icc_cache_list_len > 0)
            memcpy(crdev->icc_cache_list, old, sizeof(void *)*crdev->icc_cache_list_len);
        memset(&crdev->icc_cache_list[crdev->icc_cache_list_len], 0,
            (crdev->num_render_threads - crdev->icc_cache_list_len) * sizeof(void *));
        crdev->icc_cache_list_len = crdev->num_render_threads;
        gs_free_object(mem, old, "clist_render_setup_threads");
    }

    /* Loop creating the devices and semaphores for each thread, then start them */
    for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count);
            i++, band += crdev->thread_lookahead_direction) {
        gx_device *ndev;
        clist_render_thread_control_t *thread = &(crdev->render_threads[i]);

        ndev = setup_device_and_mem_for_thread(chunk_base_mem, dev, false, &crdev->icc_cache_list[i]);
        if (ndev == NULL) {
            code = gs_error_VMerror;	/* set code to an error for cleanup after the loop */
            break;
        }

        thread->cdev = ndev;
        thread->memory = ndev->memory;
        thread->band = -1;              /* a value that won't match any valid band */
        thread->options = options;
        thread->buffer = NULL;
        if (options && options->init_buffer_fn) {
            code = options->init_buffer_fn(options->arg, dev, thread->memory, dev->width, band_height, &thread->buffer);
            if (code < 0)
                break;
        }

        /* create the buf device for this thread, and allocate the semaphores */
        if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                &(thread->bdev), ndev,
                                band*crdev->page_band_height, NULL,
                                thread->memory, &(crdev->color_usage_array[0])) < 0))
            break;
        if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL ||
            (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) {
            code = gs_error_VMerror;
            break;
        }
        /* Start thread 'i' to do band */
        if ((code = clist_start_render_thread(dev, i, band)) < 0)
            break;
    }
    /* If the code < 0, the last thread creation failed -- clean it up */
    if (code < 0) {
        band -= crdev->thread_lookahead_direction;	/* update for 'next_band' usage */
        /* the following relies on 'free' ignoring NULL pointers */
        gx_semaphore_free(crdev->render_threads[i].sema_group);
        gx_semaphore_free(crdev->render_threads[i].sema_this);
        if (crdev->render_threads[i].bdev != NULL)
            cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev);
        if (crdev->render_threads[i].cdev != NULL) {
            gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev;

            /* Close the file handles, but don't delete (unlink) the files */
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.bfile, thread_cdev->page_info.bfname, false);
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_info.cfile, thread_cdev->page_info.cfname, false);
            thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

            gdev_prn_free_memory((gx_device *)thread_cdev);
            gs_free_object(crdev->render_threads[i].memory, thread_cdev,
            "clist_setup_render_threads");
        }
        if (crdev->render_threads[i].buffer != NULL && options && options->free_buffer_fn != NULL) {
            options->free_buffer_fn(options->arg, dev, crdev->render_threads[i].memory, crdev->render_threads[i].buffer);
            crdev->render_threads[i].buffer = NULL;
        }
        if (crdev->render_threads[i].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[i].memory);
            crdev->render_threads[i].memory = NULL;
        }
    }
    /* If we weren't able to create at least one thread, punt   */
    /* Although a single thread isn't any more efficient, the   */
    /* machinery still works, so that's OK.                     */
    if (i == 0) {
        if (crdev->render_threads[0].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[0].memory);
            /* free up the locking wrapper if we allocated one */
            if (chunk_base_mem != mem) {
                gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem);
                gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)");
            }
        }
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        /* restore the file pointers */
        if (cdev->page_info.cfile == NULL) {
            char fmode[4];

            strcpy(fmode, "a+");        /* file already exists and we want to re-use it */
            strncat(fmode, gp_fmode_binary_suffix, 1);
            cdev->page_info.io_procs->fopen(cdev->page_info.cfname, fmode, &cdev->page_info.cfile,
                                mem, cdev->bandlist_memory, true);
            cdev->page_info.io_procs->fseek(cdev->page_info.cfile, 0, SEEK_SET, cdev->page_info.cfname);
            cdev->page_info.io_procs->fopen(cdev->page_info.bfname, fmode, &cdev->page_info.bfile,
                                mem, cdev->bandlist_memory, false);
            cdev->page_info.io_procs->fseek(cdev->page_info.bfile, 0, SEEK_SET, cdev->page_info.bfname);
        }
        emprintf1(mem, "Rendering threads not started, code=%d.\n", code);
        return_error(code);
    }
    crdev->num_render_threads = i;
    crdev->curr_render_thread = 0;
        crdev->next_band = band;

    if(gs_debug[':'] != 0)
        dmprintf1(mem, "%% Using %d rendering threads\n", i);

    return 0;
}
示例#6
0
/* Set up and start the render threads */
static int
clist_setup_render_threads(gx_device *dev, int y)
{
    gx_device_printer *pdev = (gx_device_printer *)dev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_common *cdev = (gx_device_clist_common *)cldev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gs_memory_t *mem = cdev->bandlist_memory;
    gs_memory_t *chunk_base_mem = mem->thread_safe_memory;
    gs_memory_status_t mem_status;
    gx_device *protodev;
    gs_c_param_list paramlist;
    int i, code, band;
    int band_count = cdev->nbands;
    char fmode[4];
    gs_devn_params *pclist_devn_params;
    crdev->num_render_threads = pdev->num_render_threads_requested;

    if(gs_debug[':'] != 0)
        dprintf1("%% %d rendering threads requested.\n", pdev->num_render_threads_requested);

    if (crdev->num_render_threads > band_count)
        crdev->num_render_threads = band_count; /* don't bother starting more threads than bands */

    /* Allocate and initialize an array of thread control structures */
    crdev->render_threads = (clist_render_thread_control_t *)
              gs_alloc_byte_array(mem, crdev->num_render_threads,
              sizeof(clist_render_thread_control_t), "clist_setup_render_threads" );
    /* fallback to non-threaded if allocation fails */
    if (crdev->render_threads == NULL) {
        emprintf(mem, " VMerror prevented threads from starting.\n");
        return_error(gs_error_VMerror);
    }

    memset(crdev->render_threads, 0, crdev->num_render_threads *
            sizeof(clist_render_thread_control_t));
    crdev->main_thread_data = cdev->data;               /* save data area */
    /* Based on the line number requested, decide the order of band rendering */
    /* Almost all devices go in increasing line order (except the bmp* devices ) */
    crdev->thread_lookahead_direction = (y < (cdev->height - 1)) ? 1 : -1;
    band = y / crdev->page_info.band_params.BandHeight;

    /* Close the files so we can open them in multiple threads */
    if ((code = cdev->page_info.io_procs->fclose(cdev->page_cfile, cdev->page_cfname, false)) < 0 ||
        (code = cdev->page_info.io_procs->fclose(cdev->page_bfile, cdev->page_bfname, false)) < 0) {
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        emprintf(mem, "Closing clist files prevented threads from starting.\n");
        return_error(gs_error_unknownerror); /* shouldn't happen */
    }
    cdev->page_cfile = cdev->page_bfile = NULL;
    strcpy(fmode, "r");                 /* read access for threads */
    strncat(fmode, gp_fmode_binary_suffix, 1);
    /* Find the prototype for this device (needed so we can copy from it) */
    for (i=0; (protodev = (gx_device *)gs_getdevice(i)) != NULL; i++)
        if (strcmp(protodev->dname, dev->dname) == 0)
            break;
    if (protodev == NULL) {
        emprintf(mem,
                 "Could not find prototype device. Rendering threads not started.\n");
        return gs_error_rangecheck;
    }

    gs_c_param_list_write(&paramlist, mem);
    if ((code = gs_getdeviceparams(dev, (gs_param_list *)&paramlist)) < 0) {
        emprintf1(mem,
                  "Error getting device params, code=%d. Rendering threads not started.\n",
                  code);
        return code;
    }

    /* If the 'mem' is not thread safe, we need to wrap it in a locking memory */
    gs_memory_status(chunk_base_mem, &mem_status);
    if (mem_status.is_thread_safe == false) {
            return_error(gs_error_VMerror);
    }

    /* Loop creating the devices and semaphores for each thread, then start them */
    for (i=0; (i < crdev->num_render_threads) && (band >= 0) && (band < band_count);
            i++, band += crdev->thread_lookahead_direction) {
        gx_device *ndev;
        gx_device_clist *ncldev;
        gx_device_clist_common *ncdev;
        clist_render_thread_control_t *thread = &(crdev->render_threads[i]);

        /* Every thread will have a 'chunk allocator' to reduce the interaction
         * with the 'base' allocator which has 'mutex' (locking) protection.
         * This improves performance of the threads.
         */
        if ((code = gs_memory_chunk_wrap(&(thread->memory), chunk_base_mem )) < 0) {
            emprintf1(mem, "chunk_wrap returned error code: %d\n", code);
            break;
        }

        thread->band = -1;              /* a value that won't match any valid band */
        if ((code = gs_copydevice((gx_device **) &ndev, protodev, thread->memory)) < 0) {
            code = 0;           /* even though we failed, no cleanup needed */
            break;
        }
        ncldev = (gx_device_clist *)ndev;
        ncdev = (gx_device_clist_common *)ndev;
        gx_device_fill_in_procs(ndev);
        ((gx_device_printer *)ncdev)->buffer_memory = ncdev->memory =
                ncdev->bandlist_memory = thread->memory;
        gs_c_param_list_read(&paramlist);
        ndev->PageCount = dev->PageCount;       /* copy to prevent mismatch error */
#if CMM_THREAD_SAFE
        ndev->icc_struct = dev->icc_struct;  /* Set before put params */
        rc_increment(ndev->icc_struct);
#endif
        if ((code = gs_putdeviceparams(ndev, (gs_param_list *)&paramlist)) < 0)
            break;
        /* In the case of a separation device, we need to make sure we get the
           devn params copied over */
        pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
        if (pclist_devn_params != NULL) {
            code = devn_copy_params(dev, (gx_device*) ncdev);
            if (code < 0) return_error(gs_error_VMerror);
        }
        ncdev->page_uses_transparency = cdev->page_uses_transparency;
        if_debug3('{',"[{]MT clist device = 0x%x profile = 0x%x handle = 0x%x\n", 
                  ncdev,
                  ncdev->icc_struct->device_profile[0],
                  ncdev->icc_struct->device_profile[0]->profile_handle);
        /* gdev_prn_allocate_memory sets the clist for writing, creating new files.
         * We need  to unlink those files and open the main thread's files, then
         * reset the clist state for reading/rendering
         */
        if ((code = gdev_prn_allocate_memory(ndev, NULL, ndev->width, ndev->height)) < 0)
            break;
        /* Needed for case when the target has cielab profile and pdf14 device
           has a RGB profile stored in the profile list of the clist */
        ncdev->trans_dev_icc_hash = cdev->trans_dev_icc_hash;
        thread->cdev = ndev;
        /* close and unlink the temp files just created */
        cdev->page_info.io_procs->fclose(ncdev->page_cfile, ncdev->page_cfname, true);
        cdev->page_info.io_procs->fclose(ncdev->page_bfile, ncdev->page_bfname, true);
        /* open the main thread's files for this thread */
        if ((code=cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &ncdev->page_cfile,
                            thread->memory, thread->memory, true)) < 0 ||
             (code=cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &ncdev->page_bfile,
                            thread->memory, thread->memory, false)) < 0)
            break;
        clist_render_init(ncldev);      /* Initialize clist device for reading */
        ncdev->page_bfile_end_pos = cdev->page_bfile_end_pos;
        /* Use the same link cache in each thread and the same profile table.
           The threads are maintained until clist_finish_page.  At which
           point, the threads are torn down and the master clist reader device
           is destroyed along with the icc_table and the icc_cache_cl */
#if CMM_THREAD_SAFE
        ncdev->icc_cache_cl = cdev->icc_cache_cl;
#else
        ncdev->icc_cache_cl = gsicc_cache_new(crdev->memory);
#endif
        ncdev->icc_table = cdev->icc_table;
        /* create the buf device for this thread, and allocate the semaphores */
        if ((code = gdev_create_buf_device(cdev->buf_procs.create_buf_device,
                                &(thread->bdev), cdev->target,
                                band*crdev->page_band_height, NULL,
                                thread->memory, clist_get_band_complexity(dev,y)) < 0))
            break;
        if ((thread->sema_this = gx_semaphore_alloc(thread->memory)) == NULL ||
            (thread->sema_group = gx_semaphore_alloc(thread->memory)) == NULL) {
            code = gs_error_VMerror;
            break;
        }
        /* Start thread 'i' to do band */
        if ((code = clist_start_render_thread(dev, i, band)) < 0)
            break;
    }
    gs_c_param_list_release(&paramlist);
    /* If the code < 0, the last thread creation failed -- clean it up */
    if (code < 0) {
        /* the following relies on 'free' ignoring NULL pointers */
        gx_semaphore_free(crdev->render_threads[i].sema_group);
        gx_semaphore_free(crdev->render_threads[i].sema_this);
        if (crdev->render_threads[i].bdev != NULL)
            cdev->buf_procs.destroy_buf_device(crdev->render_threads[i].bdev);
        if (crdev->render_threads[i].cdev != NULL) {
            gx_device_clist_common *thread_cdev = (gx_device_clist_common *)crdev->render_threads[i].cdev;

            /* Close the file handles, but don't delete (unlink) the files */
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_bfile, thread_cdev->page_bfname, false);
            thread_cdev->page_info.io_procs->fclose(thread_cdev->page_cfile, thread_cdev->page_cfname, false);
            thread_cdev->do_not_open_or_close_bandfiles = true; /* we already closed the files */

            gdev_prn_free_memory((gx_device *)thread_cdev);
            gs_free_object(crdev->render_threads[i].memory, thread_cdev,
            "clist_setup_render_threads");
        }
        if (crdev->render_threads[i].memory != NULL)
            gs_memory_chunk_release(crdev->render_threads[i].memory);
    }
    /* If we weren't able to create at least one thread, punt   */
    /* Although a single thread isn't any more efficient, the   */
    /* machinery still works, so that's OK.                     */
    if (i == 0) {
        if (crdev->render_threads[0].memory != NULL) {
            gs_memory_chunk_release(crdev->render_threads[0].memory);
            /* free up the locking wrapper if we allocated one */
            if (chunk_base_mem != mem) {
                gs_memory_locked_release((gs_memory_locked_t *)chunk_base_mem);
                gs_free_object(mem, chunk_base_mem, "clist_setup_render_threads(locked allocator)");
            }
        }
        gs_free_object(mem, crdev->render_threads, "clist_setup_render_threads");
        crdev->render_threads = NULL;
        /* restore the file pointers */
        if (cdev->page_cfile == NULL) {
            char fmode[4];

            strcpy(fmode, "a+");        /* file already exists and we want to re-use it */
            strncat(fmode, gp_fmode_binary_suffix, 1);
            cdev->page_info.io_procs->fopen(cdev->page_cfname, fmode, &cdev->page_cfile,
                                mem, cdev->bandlist_memory, true);
            cdev->page_info.io_procs->fseek(cdev->page_cfile, 0, SEEK_SET, cdev->page_cfname);
            cdev->page_info.io_procs->fopen(cdev->page_bfname, fmode, &cdev->page_bfile,
                                mem, cdev->bandlist_memory, false);
            cdev->page_info.io_procs->fseek(cdev->page_bfile, 0, SEEK_SET, cdev->page_bfname);
        }
        emprintf1(mem, "Rendering threads not started, code=%d.\n", code);
        return_error(code);
    }
    crdev->num_render_threads = i;
    crdev->curr_render_thread = 0;

    if(gs_debug[':'] != 0)
        dprintf1("%% Using %d rendering threads\n", i);

    return 0;
}
示例#7
0
/*
 * Caller should make sure that this device supports saved_pages:
 * dev_proc(dev, dev_spec_op)(dev, gxdso_supports_saved_pages, NULL, 0) == 1
 *
 * Returns < 0 if error, 1 if erasepage needed, 0 if no action needed.
 */
int
gx_saved_pages_param_process(gx_device_printer *pdev, byte *param, int param_size)
{
    byte *param_scan = param;
    int param_left = param_size;
    byte *token;
    int token_size, code, printed_count, collated_copies = 1;
    int tmp_num;			/* during token scanning loop */
    int erasepage_needed = 0;

    while (pdev->child)
        pdev = (gx_device_printer *)pdev->child;

    while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) {

        switch (param_find_key(token, token_size)) {
          case PARAM_BEGIN:
            if (pdev->saved_pages_list == NULL) {
                if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL)
                    return_error(gs_error_VMerror);

                /* We need to change to clist mode. Always uses clist when saving pages */
                pdev->saved_pages_list->save_banding_type = pdev->space_params.banding_type;
                pdev->space_params.banding_type = BandingAlways;
                if ((code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height)) < 0)
                    return code;
                erasepage_needed |= 1;
            }
            break;

          case PARAM_END:
            if (pdev->saved_pages_list != NULL) {
                /* restore to what was set before the "begin" */
                pdev->space_params.banding_type = pdev->saved_pages_list->save_banding_type;
                gx_saved_pages_list_free(pdev->saved_pages_list);
                pdev->saved_pages_list = NULL;
                /* We may need to change from clist mode since we forced clist when saving pages */
                code = gdev_prn_reallocate_memory((gx_device *)pdev, &pdev->space_params, pdev->width, pdev->height);
                if (code < 0)
                    return code;
                erasepage_needed |= 1;       /* make sure next page is erased */
            }
            break;

          case PARAM_FLUSH:
            if (pdev->saved_pages_list != NULL) {
                /* Save the collated copy count so the list we return will have it */
                collated_copies = pdev->saved_pages_list->collated_copies;
                gx_saved_pages_list_free(pdev->saved_pages_list);
            }
            /* Always return with an empty list, even if we weren't saving previously */
            if ((pdev->saved_pages_list = gx_saved_pages_list_new(pdev)) == NULL)
                return_error(gs_error_VMerror);
            /* restore the original count */
            pdev->saved_pages_list->collated_copies = collated_copies;
            break;

          case PARAM_COPIES:			/* copies requires a number next */
            /* make sure that we have a list */
            if (pdev->saved_pages_list == NULL) {
                return_error(gs_error_rangecheck);	/* copies not allowed before a 'begin' */
            }
            /* Move to past 'copies' token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;

            if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL ||
                 param_find_key(token, token_size) != PARAM_NUMBER) {
                emprintf(pdev->memory, "gx_saved_pages_param_process: copies not followed by number.\n");
                return_error(gs_error_typecheck);
            }
            if (sscanf((const char *)token, "%d", &tmp_num) != 1) {
                emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                code = gs_error_typecheck;
                return code;
            }
            pdev->saved_pages_list->collated_copies = tmp_num;	/* save it for our loop */
            break;

          case PARAM_PRINT:
            /* Move to past 'print' token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;

            code = param_left;			/* in case list is NULL, skip rest of string */
            if (pdev->saved_pages_list != NULL) {
                if ((code = gx_saved_pages_list_print(pdev, pdev->saved_pages_list,
                                                 param_scan, param_left, &printed_count)) < 0)
                    return code;
                erasepage_needed |= 1;       /* make sure next page is erased */
            }
            /* adjust for all of the print parameters */
            token_size += code;
            break;

          /* We are expecting an action keyword, so other keywords and tokens */
          /* are not valid here (mostly the 'print' parameters).              */
          default:
            {
                byte *bad_token = gs_alloc_string(pdev->memory, token_size+1, "saved_pages_param_process");
                byte *param_string = gs_alloc_string(pdev->memory, param_size+1, "saved_pages_param_process");
                if (bad_token != NULL && param_string != NULL) {
                    memcpy(bad_token, token, token_size);
                    bad_token[token_size] = 0;          /* terminate string */
                    memcpy(param_string, param, param_size);
                    param_string[param_size] = 0;          /* terminate string */
                    emprintf2(pdev->memory, "*** Invalid saved-pages token '%s'\n *** in param string '%s'\n",
                              bad_token, param_string);
                    gs_free_string(pdev->memory, bad_token, token_size+1,  "saved_pages_param_process");
                    gs_free_string(pdev->memory, param_string, param_size+1,  "saved_pages_param_process");
                }
            }
        }
        /* Move to next token */
        param_left -= token - param_scan + token_size;
        param_scan = token + token_size;

    }
    return erasepage_needed;
}
示例#8
0
/*
 * Print selected pages from the list to on the selected device. The
 * saved_pages_list is NOT modified, allowing for reprint / recovery
 * print. Each saved_page is printed on a separate page (unlike the
 * gdev_prn_render_pages above which prints several saved_pages on
 * a single "master" page, performing imposition).
 *
 * This is primarily intended to allow printing in non-standard order
 * (reverse, odd, even) or producing collated copies for a job.
 *
 * On success return the number of bytes consumed or error code < 0.
 * The printed_count will contain the number of pages printed.
 *
 * -------------------------------------------------------------------
 *
 * The param string may begin with whitespace. The string is parsed
 * and the selected pages are printed. There may be any number of ranges
 * and or keywords separated by whitespace and/or comma ','.
 *
 * NB: The pdev printer device's PageCount is updated to reflect the
 *     total number of pages produced (per the spec for this parameter)
 *     since we may be producing multiple collated copies.
 *     Also the list PageCount is updated after printing since
 *     there may be a subsequent 'print' action.
 * keywords:
 *	copies #	Set the number of copies for subsequent printing actions
 *                      "copies 1" resets to a single copy
 *	normal		All pages are printed in normal order
 *	reverse		All pages are printed in reverse order
 *         The following two options may be useful for duplexing.
 *	odd		All odd pages are printed, e.g. 1, 3, 5, ...
 *	even		All even pages are printed, e.g. 2, 4, 6, ...
 *                      NB: an extra blank page will be printed if the list
 *                      has an odd number of pages.
 *      even0pad        All even pages, but no extra blank page if there are
 *                      an odd number of pages on the list.
 * range syntax:
 *	range range	multiple ranges are separated by commas ','
 *			and/or whitespace.
 *	#		a specific page number is a valid range
 *
 *	inclusive ranges below can have whitespace before
 *	or after the dash '-'.
 *	#-#		a range consisting of all pages from the first
 *			page # up to (and including) the second page #.
 *	#-*		all pages from # up through the last page
 *			"1-*" is equivalent to "normal"
 *	*-#		all pages from the last up through # page.
 *			"reverse" is equivalent to "*-1"
 */
int
gx_saved_pages_list_print(gx_device_printer *pdev, gx_saved_pages_list *list,
                          byte *param, int param_size, int *printed_count)
{
    byte *param_scan = NULL;
    int param_left;
    int start_page = 0;				/* 0 means start_page unknown */
    int end_page = 0;				/* < 0 means waiting for the end of a # - # range */
                                                /* i.e, a '-' was scanned. 0 means unknown */
    int tmp_num;				/* during token scanning loop */
    int code = 0, endcode = 0;
    byte *token;
    int copy, token_size;
    gx_device_clist_reader *crdev = (gx_device_clist_reader *)pdev;
    /* the following are used so we can go back to the original state */
    bool save_bg_print = false;                 /* arbitrary, silence warning */
    bool save_bandfile_open_close = false;      /* arbitrary, silence warning */
    gx_saved_page saved_page;
    clist_file_ptr saved_files[2];

    /* save the current (empty) page while we print  */
    if ((code = do_page_save(pdev, &saved_page, saved_files)) < 0) {
        emprintf(pdev->memory, "gx_saved_pages_list_print: Error getting device params\n");
        goto out;
    }

    /* save_page leaves the clist in writer mode, so prepare for reading clist */
    /* files. When we are done with printing, we'll go back to write mode.     */
    if ((code = clist_close_writer_and_init_reader((gx_device_clist *)pdev)) < 0)
        goto out;

    /* While printing, disable the saved_pages mode and bg_print */
    pdev->saved_pages_list = NULL;
    save_bg_print = pdev->bg_print_requested;

    /* Inhibits modifying the clist at end of output_page */
    save_bandfile_open_close = crdev->do_not_open_or_close_bandfiles;
    crdev->do_not_open_or_close_bandfiles = true;

    pdev->PageCount = list->PageCount;		/* adjust to value last printed */

    /* loop producing the number of copies */
    /* Note: list->collated_copies may change if 'copies' param follows the 'print' */
    for (copy = 1; copy <= list->collated_copies; copy++) {
        int page_skip = 0;
        bool do_blank_page_pad;
        int page;

        /* Set to start of 'print' params to do collated copies */
        param_scan = param;
        param_left = param_size;
        while ((token = param_parse_token(param_scan, param_left, &token_size)) != NULL) {
            saved_pages_key_enum key;

            page = 0;
            do_blank_page_pad = false;			/* only set for EVEN */
            key = param_find_key(token, token_size);
            switch (key) {
              case PARAM_DASH:
                if (start_page == 0) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: '-' unexpected\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                end_page = -1;		/* the next number will end a range */
                break;

              case PARAM_STAR:
                page = list->count;		/* last page */
              case PARAM_NUMBER:
                if (page == 0) {
                     if (sscanf((const char *)token, "%d", &page) != 1) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                         code = gs_error_typecheck;
                         goto out;
                     }
                }
                if (start_page == 0) {
                    start_page = page;		/* first number seen */
                } else {
                    /* a second number was seen after the start_page was set */
                    if (end_page < 0) {
                        end_page = page;		/* end of a '# - #' range */
                        page_skip = (end_page >= start_page) ? 1 : -1;
                    } else {
                        /* 'page' was NOT part of a range after printing 'page' will start a new range */
                        end_page = start_page;	/* single page */
                        page_skip = 1;
                    }
                }
                break;

              case PARAM_COPIES:			/* copies requires a number next */
                /* Move to past 'copies' token */
                param_left -= token - param_scan + token_size;
                param_scan = token + token_size;

                if ((token = param_parse_token(param_scan, param_left, &token_size)) == NULL ||
                     param_find_key(token, token_size) != PARAM_NUMBER) {
                    emprintf(pdev->memory, "gx_saved_pages_list_print: copies not followed by number.\n");
                    code = gs_error_typecheck;
                    goto out;
                }
                if (sscanf((const char *)token, "%d", &tmp_num) != 1) {
                    emprintf1(pdev->memory, "gx_saved_pages_list_print: Number format error '%s'\n", token);
                    code = gs_error_typecheck;
                    goto out;
                }
                list->collated_copies = tmp_num;	/* save it for our loop */
                break;

              case PARAM_NORMAL:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 1;
                break ;

              case PARAM_REVERSE:			/* sets both start and end */
                start_page = list->count;
                end_page = 1;
                page_skip = -1;
                break;

              case PARAM_EVEN:			/* sets both start and end */
                do_blank_page_pad = (list->count & 1) != 0;	/* pad if odd */
              case PARAM_EVEN0PAD:		/* sets both start and end */
                start_page = 2;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_ODD:			/* sets both start and end */
                start_page = 1;
                end_page = list->count;
                page_skip = 2;
                break ;

              case PARAM_UNKNOWN:
              case PARAM_BEGIN:
              case PARAM_END:
              case PARAM_FLUSH:
              case PARAM_PRINT:
                token_size = 0;			/* non-print range token seen */
            }
            if (end_page > 0) {
                /* Here we have a range to print since start and end are known */
                int curr_page = start_page;
                gx_saved_pages_list_element *curr_elem = NULL;

                /* get the start_page saved_page */
                if (start_page <= list->count) {
                    for (curr_elem = list->head; curr_elem->sequence_number != start_page;
                                curr_elem = curr_elem->next) {
                        if (curr_elem->next == NULL) {
                             emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", start_page);
                             code = gs_error_rangecheck;;
                             goto out;
                        }
                    }
                }

                for ( ; curr_elem != NULL; ) {

                    /* print the saved page from the current curr_elem */

                    if ((code = gx_output_saved_page(pdev, curr_elem->page)) < 0)
                        goto out;

                    curr_page += page_skip;
                    if (page_skip >= 0) {
                        if (curr_page > end_page)
                            break;
                        curr_elem = curr_elem->next;
                        if (page_skip > 1)
                            curr_elem = curr_elem->next;
                    } else {
                        /* reverse print order */
                        if (curr_page < end_page)
                            break;
                        curr_elem = curr_elem->prev;
                        /* Below is not needed since we never print reverse even/odd */
                        if (page_skip < -1)
                            curr_elem = curr_elem->prev;
                    }
                    if (curr_elem == NULL) {
                         emprintf1(pdev->memory, "gx_saved_pages_list_print: page %d not found.\n", curr_page);
                         code = gs_error_rangecheck;;
                         goto out;
                    }
                }

                /* If we were printing EVEN, we may need to spit out a blank 'pad' page */
                if (do_blank_page_pad) {
                    /* print the empty page we had upon entry */
                    /* FIXME: Note that the page size may not match the last odd page */
                    if ((code = gx_output_saved_page(pdev, &saved_page)) < 0)
                        goto out;
                }

                /* After printing, reset to handle next page range */
                start_page = (start_page == end_page) ? page : 0;   /* if single page, set start_page */
                                                                    /* from the number scanned above  */
                end_page = 0;
            }
            if (token_size == 0)
                break;				/* finished with print ranges */

            /* Move to next token */
            param_left -= token - param_scan + token_size;
            param_scan = token + token_size;
        }
    }
out:
    /* restore the device parameters saved upon entry */
    *printed_count = pdev->PageCount - list->PageCount;
    list->PageCount = pdev->PageCount;		/* retain for subsequent print action */
    pdev->saved_pages_list = list;
    pdev->bg_print_requested = save_bg_print;
    crdev->do_not_open_or_close_bandfiles = save_bandfile_open_close;

    /* load must be after we've set saved_pages_list which forces clist mode. */
    do_page_load(pdev, &saved_page, saved_files);

    /* Finally, do the finish page which will reset the clist to empty and write mode */
    endcode = clist_finish_page((gx_device *)pdev, true);
    return code < 0 ? code : endcode < 0 ? endcode : param_scan - param;
}