~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/gfx/src/xprintutil/xprintutil.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* 
 
3
 * The contents of this file are subject to the Mozilla Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/MPL/
 
7
 * 
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 * 
 
13
 * The Original Code is the X11 print system utilities library.
 
14
 * 
 
15
 * The Initial Developer of the Original Code is Roland Mainz 
 
16
 * <roland.mainz@informatik.med.uni-giessen.de>.
 
17
 * All Rights Reserved.
 
18
 * 
 
19
 * Contributor(s):
 
20
 * 
 
21
 * Alternatively, the contents of this file may be used under the
 
22
 * terms of the GNU General Public License Version 2 or later (the
 
23
 * "GPL"), in which case the provisions of the GPL are applicable 
 
24
 * instead of those above.  If you wish to allow use of your 
 
25
 * version of this file only under the terms of the GPL and not to
 
26
 * allow others to use your version of this file under the MPL,
 
27
 * indicate your decision by deleting the provisions above and
 
28
 * replace them with the notice and other provisions required by
 
29
 * the GPL.  If you do not delete the provisions above, a recipient
 
30
 * may use your version of this file under either the MPL or the
 
31
 * GPL.
 
32
 */
 
33
 
 
34
#include "xprintutil.h"
 
35
 
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
#include <ctype.h>
 
39
#include <stdio.h>
 
40
#include <limits.h>
 
41
#include <errno.h>
 
42
#include <locale.h>
 
43
 
 
44
#ifdef XPU_USE_NSPR
 
45
#include "plstr.h"
 
46
#undef strtok_r
 
47
#define strtok_r(s1, s2, x) PL_strtok_r((s1), (s2), (x))
 
48
#endif /* USE_MOZILLA_TYPES */
 
49
 
 
50
/* List of tokens which can be used to separate entries in the 
 
51
 * $XPSERVERLIST env var */
 
52
static const char XPServerListSeparators[] = " \t\v\n\r\f";
 
53
 
 
54
/* conformace only; X11 API does (currrently) not make use of |const|. 
 
55
 * If Xlib API gets fixed these macros can be turned into empty 
 
56
 * placeholders... (|#define MAKE_STRING_WRITABLE(x)|) :-)
 
57
 */
 
58
#define MAKE_STRING_WRITABLE(str) (((str)?((str) = strdup(str)):0))
 
59
#define FREE_WRITABLE_STRING(str) free((void *)(str))
 
60
#define STRING_AS_WRITABLE(str) ((char *)(str))
 
61
 
 
62
/* Local prototypes */
 
63
static const char *XpuGetDefaultXpPrintername(void);
 
64
static const char *XpuGetXpServerList( void );
 
65
static const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr );
 
66
static const char *XpuGetCurrentAttributeGroup( void **vcptr );
 
67
static void XpuDisposeEnumerateXpAttributeValue( void **vc );
 
68
static Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext,
 
69
                                           const char **tray_name,
 
70
                                           const char **medium_name, int *mbool, 
 
71
                                           float *ma1, float *ma2, float *ma3, float *ma4,
 
72
                                           void **vcptr );
 
73
static void XpuDisposeEnumerateMediumSourceSizes( void **vc );
 
74
 
 
75
/*
 
76
** XprintUtil functions start with Xpu
 
77
**
 
78
*/
 
79
 
 
80
int XpuCheckExtension( Display *pdpy )
 
81
{
 
82
  char *display = XDisplayString(pdpy);
 
83
  short major = 0,
 
84
        minor = 0;
 
85
 
 
86
  if( XpQueryVersion(pdpy, &major, &minor) != 0 )
 
87
  {
 
88
    XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' %d %d\n", XPU_NULLXSTR(display), (int)major, (int)minor));
 
89
    return(1);
 
90
  }
 
91
  else
 
92
  {
 
93
    XPU_DEBUG_ONLY(printf("XpuCheckExtension: XpQueryVersion '%s' returned 0(=Xprint not supported)\n", XPU_NULLXSTR(display)));
 
94
  }
 
95
  
 
96
  return(0);
 
97
}
 
98
 
 
99
/* Get the default printer name from the XPRINTER env var.
 
100
 * If XPRINTER env var is not present looks for PDPRINTER, LPDEST, and
 
101
 * PRINTER (in that order)
 
102
 * See CDE's DtPrintSetupBox(3) manual page, too...
 
103
 */
 
104
static
 
105
const char *XpuGetDefaultXpPrintername(void)
 
106
{
 
107
  const char *s;
 
108
  /* BUG/TODO: XpPrinter resource needs to be sourced, too... */
 
109
  s = getenv("XPRINTER");
 
110
  if( !s )
 
111
  {
 
112
    s = getenv("PDPRINTER");
 
113
    if( !s )
 
114
    {
 
115
      s = getenv("LPDEST");
 
116
      if( !s )
 
117
      {
 
118
        s = getenv("PRINTER");
 
119
      }
 
120
    }
 
121
  }  
 
122
  return s;
 
123
}
 
124
 
 
125
static
 
126
const char *XpuGetXpServerList( void )
 
127
{
 
128
  const char *s;
 
129
  /* BUG/TODO: XpServerList resource needs to be sourced first, then append 
 
130
   * contents of XPSERVERLIST, then remove duplicates...
 
131
   */
 
132
  s = getenv("XPSERVERLIST"); 
 
133
  if( s == NULL )
 
134
    s = "";
 
135
    
 
136
  return(s);
 
137
}
 
138
 
 
139
 
 
140
Bool XpuXprintServersAvailable( void )
 
141
{
 
142
  const char *s;
 
143
  int         c = 0;
 
144
  /* BUGs/ToDo:
 
145
   * - XpServerList resource needs to be sourced, too...
 
146
   *   (see comment for |XpuGetXpServerList|, too)
 
147
   * - There should be some validation whether the server entries
 
148
   *   are
 
149
   *     a) valid (easy :)
 
150
   *   and
 
151
   *     b) available (hard to implement when XOpenDisplay() should be avoided)
 
152
   */
 
153
  s = getenv("XPSERVERLIST");
 
154
  /* Check if serverlist is non-empty */
 
155
  if (s)
 
156
  {
 
157
    while( *s++ )
 
158
    {
 
159
      if( !isspace(*s) )
 
160
        c++;
 
161
    }
 
162
  }
 
163
  /* a valid server name must at least contain the ':'-seperator
 
164
   * and a number (e.g. ":1") */
 
165
  return( c >= 2 );
 
166
}
 
167
 
 
168
 
 
169
static 
 
170
int XpuGetPrinter2( char *printer, char *display, Display **pdpyptr, XPContext *pcontextptr )
 
171
{
 
172
  Display   *pdpy;
 
173
  XPContext  pcontext;
 
174
  
 
175
  XPU_DEBUG_ONLY(printf("XpuGetPrinter2: probing display '%s' for '%s'\n", XPU_NULLXSTR(display), XPU_NULLXSTR(printer)));
 
176
  
 
177
  if( (pdpy = XOpenDisplay(display)) != NULL )
 
178
  {
 
179
    if( XpuCheckExtension(pdpy) )
 
180
    {
 
181
      XPPrinterList list;
 
182
      int           list_count;
 
183
      
 
184
      /* get list of available printers... */
 
185
      list = XpGetPrinterList(pdpy, printer, &list_count);        
 
186
      if( list != NULL ) XpFreePrinterList(list);
 
187
      
 
188
      /* ...and check if printer exists... */
 
189
      if( (list != NULL) && (list_count > 0) )
 
190
      {
 
191
        if( (pcontext = XpCreateContext(pdpy, printer)) != None )
 
192
        {
 
193
          *pdpyptr     = pdpy;
 
194
          *pcontextptr = pcontext;
 
195
          return(1);
 
196
        }
 
197
        
 
198
        XPU_DEBUG_ONLY(printf("XpuGetPrinter2: could not create print context for '%s'\n", XPU_NULLXSTR(printer)));
 
199
      }
 
200
    }
 
201
    else
 
202
    {
 
203
      XPU_DEBUG_ONLY(printf("display '%s' does not support the Xprint extension\n", XPU_NULLXSTR(display)));
 
204
    }  
 
205
 
 
206
    XCloseDisplay(pdpy);
 
207
    return(0);
 
208
  }
 
209
  else
 
210
  {
 
211
    XPU_DEBUG_ONLY(printf("could not open display '%s'\n", XPU_NULLXSTR(display)));
 
212
    return(0);
 
213
  }
 
214
}
 
215
 
 
216
 
 
217
/* acceps "printer" or "printer@display" */
 
218
int XpuGetPrinter( const char *arg_printername, Display **pdpyptr, XPContext *pcontextptr )
 
219
{
 
220
  Display       *pdpy;
 
221
  XPContext      pcontext;
 
222
  char          *printername;
 
223
  char          *s;
 
224
  char          *tok_lasts;
 
225
  
 
226
  *pdpyptr     = NULL;
 
227
  *pcontextptr = None;
 
228
  
 
229
  XPU_DEBUG_ONLY(printf("XpuGetPrinter: looking for '%s'\n", XPU_NULLXSTR(arg_printername)));
 
230
  
 
231
  /* strtok_r will modify string - duplicate it first... */
 
232
  printername = strdup(arg_printername);
 
233
  if( printername == NULL )
 
234
    return(0);
 
235
  
 
236
  if( (s = strtok_r(printername, "@", &tok_lasts)) != NULL )
 
237
  {
 
238
    char *name = s;
 
239
    char *display = strtok_r(NULL, "@", &tok_lasts);
 
240
    
 
241
    /* if we have a display - open it and grab printer */
 
242
    if( display != NULL )
 
243
    {
 
244
      if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) )
 
245
      {
 
246
        free(printername);
 
247
        return(1);
 
248
      }
 
249
    }
 
250
    /* if we did not get a display, travel througth all displays */
 
251
    else
 
252
    {
 
253
      char *sl = strdup(XpuGetXpServerList());
 
254
      
 
255
      if( sl != NULL )
 
256
      {
 
257
        for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ; 
 
258
             display != NULL ; 
 
259
             display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) )
 
260
        {       
 
261
          if( XpuGetPrinter2(name, display, pdpyptr, pcontextptr) )
 
262
          {
 
263
            free(sl);
 
264
            free(printername);
 
265
            return(1);
 
266
          } 
 
267
        }
 
268
        
 
269
        free(sl);
 
270
      }
 
271
    }
 
272
  }
 
273
  
 
274
  free(printername);
 
275
  XPU_DEBUG_ONLY(printf("XpuGetPrinter: failure\n"));
 
276
  
 
277
  return(0);
 
278
}
 
279
 
 
280
 
 
281
void XpuClosePrinterDisplay(Display *pdpy, XPContext pcontext)
 
282
{
 
283
  if( pdpy )
 
284
  {
 
285
    if( pcontext != None )
 
286
      XpDestroyContext(pdpy, pcontext);
 
287
      
 
288
    XCloseDisplay(pdpy);
 
289
  }
 
290
}
 
291
 
 
292
void XpuSetOneAttribute( Display *pdpy, XPContext pcontext, 
 
293
                         XPAttributes type, const char *attribute_name, const char *value, XPAttrReplacement replacement_rule )
 
294
{
 
295
  /* Alloc buffer for sprintf() stuff below */
 
296
  char *buffer = (char *)malloc(strlen(attribute_name)+strlen(value)+4);
 
297
  
 
298
  if( buffer != NULL )
 
299
  {
 
300
    sprintf(buffer, "%s: %s", attribute_name, value);      
 
301
    XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule);
 
302
    free(buffer);
 
303
  }  
 
304
}
 
305
 
 
306
void XpuSetOneLongAttribute( Display *pdpy, XPContext pcontext, 
 
307
                             XPAttributes type, const char *attribute_name, long value, XPAttrReplacement replacement_rule )
 
308
{
 
309
  /* Alloc buffer for sprintf() stuff below */
 
310
  char *buffer = (char *)malloc(strlen(attribute_name)+32+4);
 
311
  
 
312
  if( buffer != NULL )
 
313
  {
 
314
    sprintf(buffer, "%s: %ld", attribute_name, value);      
 
315
    XpSetAttributes(pdpy, pcontext, type, buffer, replacement_rule);
 
316
    free(buffer);
 
317
  }  
 
318
}
 
319
 
 
320
/* Check if attribute value is supported or not
 
321
 * Use this function _only_ if XpuGetSupported{Job,Doc,Page}Attributes()
 
322
 * does not help you...
 
323
 */
 
324
int XpuCheckSupported( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, const char *query )
 
325
{
 
326
  char *value;
 
327
  void *tok_lasts;
 
328
  
 
329
  MAKE_STRING_WRITABLE(attribute_name);
 
330
  if( attribute_name == NULL )
 
331
    return(0);
 
332
    
 
333
  value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));   
 
334
  
 
335
  XPU_DEBUG_ONLY(printf("XpuCheckSupported: XpGetOneAttribute(%s) returned '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(value)));
 
336
 
 
337
  FREE_WRITABLE_STRING(attribute_name);
 
338
  
 
339
  if( value != NULL )
 
340
  {
 
341
    const char *s;
 
342
    
 
343
    for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) )
 
344
    {
 
345
      XPU_DEBUG_ONLY(printf("XpuCheckSupported: probing '%s'=='%s'\n", XPU_NULLXSTR(s), XPU_NULLXSTR(query)));
 
346
      if( !strcmp(s, query) )
 
347
      {
 
348
        XFree(value);
 
349
        XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
 
350
        return(1);
 
351
      }  
 
352
    }
 
353
    
 
354
    XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
 
355
    XFree(value);
 
356
  }  
 
357
  
 
358
  return(0);
 
359
}
 
360
 
 
361
 
 
362
int XpuSetJobTitle( Display *pdpy, XPContext pcontext, const char *title )
 
363
{
 
364
  if( XpuGetSupportedJobAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_JOB_NAME )
 
365
  {
 
366
    XpuSetOneAttribute(pdpy, pcontext, XPJobAttr, "*job-name", title, XPAttrMerge);
 
367
    return(1);
 
368
  }
 
369
  else
 
370
  {
 
371
    XPU_DEBUG_ONLY(printf("XpuSetJobTitle: XPUATTRIBUTESUPPORTED_JOB_NAME not supported ('%s')\n", XPU_NULLXSTR(title)));
 
372
    return(0); 
 
373
  }  
 
374
}
 
375
    
 
376
int XpuGetOneLongAttribute( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name, long *result )
 
377
{
 
378
  char *s;
 
379
  
 
380
  MAKE_STRING_WRITABLE(attribute_name);
 
381
  if( attribute_name == NULL )
 
382
    return(0);
 
383
  s = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));
 
384
  
 
385
  if(s && *s) 
 
386
  {
 
387
    long tmp;
 
388
    
 
389
    XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: '%s' got '%s'\n", XPU_NULLXSTR(attribute_name), XPU_NULLXSTR(s)));
 
390
    
 
391
    tmp = strtol(s, (char **)NULL, 10);
 
392
    
 
393
    if( !(((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) && 
 
394
          ((errno == ERANGE) || (errno == EINVAL))) )
 
395
    {
 
396
      *result = tmp;
 
397
      XFree(s);
 
398
      XPU_DEBUG_ONLY(printf("XpuGetOneLongAttribute: result %ld\n", *result));
 
399
      FREE_WRITABLE_STRING(attribute_name);
 
400
      return(1);
 
401
    }            
 
402
  }
 
403
  
 
404
  if( s != NULL ) 
 
405
    XFree(s);
 
406
  
 
407
  FREE_WRITABLE_STRING(attribute_name);
 
408
  
 
409
  return(0);
 
410
}
 
411
 
 
412
 
 
413
#ifdef DEBUG
 
414
/* debug only */
 
415
void dumpXpAttributes( Display *pdpy, XPContext pcontext )
 
416
{
 
417
  char *s;
 
418
  printf("------------------------------------------------\n");
 
419
  printf("--> Job\n%s\n",         s=XpuGetJobAttributes(pdpy, pcontext));     XFree(s);
 
420
  printf("--> Doc\n%s\n",         s=XpuGetDocAttributes(pdpy, pcontext));     XFree(s);
 
421
  printf("--> Page\n%s\n",        s=XpuGetPageAttributes(pdpy, pcontext));    XFree(s);
 
422
  printf("--> Printer\n%s\n",     s=XpuGetPrinterAttributes(pdpy, pcontext)); XFree(s);
 
423
  printf("--> Server\n%s\n",      s=XpuGetServerAttributes(pdpy, pcontext));  XFree(s);
 
424
  printf("image resolution %d\n", (int)XpGetImageResolution(pdpy, pcontext));
 
425
  printf("------------------------------------------------\n");
 
426
}
 
427
#endif /* DEBUG */    
 
428
 
 
429
 
 
430
typedef struct XpuIsNotifyEventContext_
 
431
{
 
432
  int event_base;
 
433
  int detail;
 
434
} XpuIsNotifyEventContext;
 
435
 
 
436
static
 
437
Bool IsXpNotifyEvent( Display *pdpy, XEvent *ev, XPointer arg )
 
438
{
 
439
  Bool match;
 
440
  XpuIsNotifyEventContext *context = (XpuIsNotifyEventContext *)arg;
 
441
  XPPrintEvent *pev = (XPPrintEvent *)ev;
 
442
  
 
443
  match = pev->type == (context->event_base+XPPrintNotify) && 
 
444
          pev->detail == context->detail;
 
445
 
 
446
  XPU_DEBUG_ONLY(printf("XpuWaitForPrintNotify: %d=IsXpNotifyEvent(%d,%d)\n",
 
447
                 (int)match,
 
448
                 (int)pev->type,
 
449
                 (int)pev->detail));
 
450
  return match;
 
451
}
 
452
 
 
453
void XpuWaitForPrintNotify( Display *pdpy, int xp_event_base, int detail )
 
454
{
 
455
  XEvent                  dummy;
 
456
  XpuIsNotifyEventContext matchcontext;
 
457
 
 
458
  matchcontext.event_base = xp_event_base;
 
459
  matchcontext.detail     = detail;
 
460
  XIfEvent(pdpy, &dummy, IsXpNotifyEvent, (XPointer)&matchcontext);
 
461
}      
 
462
 
 
463
static
 
464
const char *skip_matching_brackets(const char *start)
 
465
{
 
466
  const char *s     = start;
 
467
  int         level = 0;
 
468
  
 
469
  if( !start )
 
470
      return(NULL);
 
471
  
 
472
  do
 
473
  {
 
474
    switch(*s++)
 
475
    {
 
476
      case '\0': return(NULL);
 
477
      case '{': level++; break;
 
478
      case '}': level--; break;
 
479
    }
 
480
  } while(level > 0);
 
481
 
 
482
  return(s);
 
483
}
 
484
 
 
485
 
 
486
static
 
487
const char *search_next_space(const char *start)
 
488
{
 
489
  const char *s     = start;
 
490
  int         level = 0;
 
491
  
 
492
  if( !start )
 
493
    return(NULL);
 
494
  
 
495
  for(;;)
 
496
  {   
 
497
    if( isspace(*s) )
 
498
      return(s);
 
499
 
 
500
    if( *s=='\0' )
 
501
      return(NULL);      
 
502
 
 
503
    s++;
 
504
  }
 
505
}
 
506
 
 
507
/* PRIVATE context data for XpuEnumerateXpAttributeValue() */
 
508
typedef struct _XpuAttributeValueEnumeration
 
509
{
 
510
  char   *value;
 
511
  size_t  original_value_len; /* original length of value */
 
512
  char   *group;
 
513
  char   *start;
 
514
  char   *s;
 
515
} XpuAttributeValueEnumeration;
 
516
 
 
517
 
 
518
/* Hacked parser for Xp values and enumerations */
 
519
static
 
520
const char *XpuEnumerateXpAttributeValue( const char *value, void **vcptr )
 
521
{
 
522
  XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr;
 
523
  XpuAttributeValueEnumeration  *context;
 
524
  const char                    *tmp;
 
525
  
 
526
  if( !cptr )
 
527
    return(NULL);
 
528
    
 
529
  if( value )
 
530
  {
 
531
    XpuAttributeValueEnumeration *e;
 
532
    const char *s = value;
 
533
    Bool        isGroup = FALSE;
 
534
  
 
535
    e = (XpuAttributeValueEnumeration *)malloc(sizeof(XpuAttributeValueEnumeration));
 
536
    if( !e )
 
537
      return NULL;
 
538
  
 
539
    /* Skip leading '{'. */
 
540
    while(*s=='{' && isGroup==FALSE)
 
541
    {
 
542
      s++;
 
543
      isGroup = TRUE;
 
544
    }  
 
545
    /* Skip leading blanks. */
 
546
    while(isspace(*s))
 
547
      s++;
 
548
    
 
549
    e->group = NULL;
 
550
    
 
551
    /* Read group name. */
 
552
    if( isGroup )
 
553
    { 
 
554
      tmp = s;  
 
555
      while(!isspace(*s))
 
556
        s++;
 
557
      if(strncmp(tmp, "''", s-tmp) != 0)
 
558
      {
 
559
        e->group = strdup(tmp);
 
560
        e->group[s-tmp] = '\0';
 
561
      }
 
562
    }
 
563
  
 
564
    e->original_value_len = strlen(s);
 
565
    e->value = (char *)malloc(e->original_value_len+4); /* We may look up to three bytes beyond the string */
 
566
    strcpy(e->value, s);
 
567
    memset(e->value+e->original_value_len+1, 0, 3); /* quad termination */
 
568
    e->start = e->s = e->value;
 
569
    
 
570
    *cptr = e;
 
571
  }
 
572
  
 
573
  context = *cptr;
 
574
  
 
575
  if( !context || !context->s )
 
576
    return(NULL);
 
577
   
 
578
  /* Skip leading blanks, '\'' or '}' */
 
579
  while(isspace(*(context->s)) || *(context->s)=='\'' /*|| *(context->s)=='}'*/ )
 
580
    context->s++;
 
581
 
 
582
  if( *(context->s) == '\0' )
 
583
    return(NULL);
 
584
 
 
585
  context->start = context->s;
 
586
  if( *(context->start) == '{' )
 
587
    context->s = (char *)skip_matching_brackets(context->start);
 
588
  else
 
589
    context->s = (char *)search_next_space(context->start);
 
590
    
 
591
  /* end of string reached ? */
 
592
  if( context->s )
 
593
  {   
 
594
    *(context->s) = '\0';
 
595
    context->s++;
 
596
  }
 
597
  
 
598
  /* Check if we reached a new attribute group */
 
599
  tmp = context->start;
 
600
  while(isspace(*tmp))
 
601
    tmp++;   
 
602
  if( *tmp=='}' )
 
603
  {
 
604
    void *prev_cptr = *vcptr;
 
605
    
 
606
    tmp+=2; /* We have 3*'\0' at the end of the string - this is legal! */
 
607
    if( *tmp!='\0' )
 
608
    {
 
609
      const char *ret;
 
610
   
 
611
      /* Start the parser again */
 
612
      *vcptr = NULL;
 
613
      ret = XpuEnumerateXpAttributeValue(tmp, vcptr);
 
614
    
 
615
      /* Free old context */
 
616
      XpuDisposeEnumerateXpAttributeValue(&prev_cptr);
 
617
    
 
618
      return(ret);
 
619
    }
 
620
    else
 
621
    {
 
622
      return(NULL);
 
623
    }
 
624
  }
 
625
  
 
626
  return(context->start);   
 
627
}
 
628
 
 
629
/* Get enumeration group for last string returned by |XpuEnumerateXpAttributeValue|... */
 
630
static
 
631
const char *XpuGetCurrentAttributeGroup( void **vcptr )
 
632
{
 
633
  XpuAttributeValueEnumeration **cptr = (XpuAttributeValueEnumeration **)vcptr;
 
634
  if( !cptr )
 
635
    return(NULL);
 
636
  if( !*cptr )
 
637
    return(NULL);
 
638
    
 
639
  return((*cptr)->group);
 
640
}
 
641
 
 
642
 
 
643
static
 
644
void XpuDisposeEnumerateXpAttributeValue( void **vc )
 
645
 
646
  if( vc )
 
647
  {
 
648
    XpuAttributeValueEnumeration *context = *((XpuAttributeValueEnumeration **)vc);
 
649
    free(context->value);
 
650
    if(context->group)
 
651
      free(context->group);
 
652
    free(context);   
 
653
  }
 
654
}
 
655
 
 
656
/* parse a paper size string 
 
657
 * (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */
 
658
static
 
659
Bool XpuParseMediumSourceSize( const char *value, 
 
660
                               const char **medium_name, int *mbool, 
 
661
                               float *ma1, float *ma2, float *ma3, float *ma4 )
 
662
{
 
663
  const char *s;
 
664
  char       *d, 
 
665
             *name;
 
666
  char       *boolbuf;
 
667
  size_t      value_len;
 
668
  int         num_input_items;
 
669
  const char *cur_locale;
 
670
  
 
671
  if( value && value[0]!='{' && value[0]!='\0' )
 
672
    return(False);
 
673
    
 
674
  value_len = strlen(value);
 
675
  
 
676
  /* alloc buffer for |medium_name| and |boolbuf| in one step
 
677
   * (both must be large enougth to hold at least |strlen(value)+1| bytes) */  
 
678
  name = (char *)malloc(value_len*2 + 4);
 
679
  boolbuf = name + value_len+2; /* |boolbuf| starts directly after |name| */
 
680
  
 
681
  /* remove '{' && '}' */
 
682
  s = value;
 
683
  d = name;
 
684
  do
 
685
  {
 
686
    *d = tolower(*s);
 
687
    
 
688
    if( *s!='{' && *s!='}' )
 
689
      d++;
 
690
    
 
691
    s++;  
 
692
  }
 
693
  while(*s);
 
694
  *d = '\0';
 
695
    
 
696
  /* separate medium name from string */
 
697
  d = (char *)search_next_space(name);
 
698
  if( !d )
 
699
  {
 
700
    free(name);
 
701
    return(False);
 
702
  }  
 
703
  *d = '\0';
 
704
  *medium_name = name;
 
705
  
 
706
  /* ... continue to parse the remaining string... */
 
707
  d++;
 
708
  
 
709
 
 
710
  /* Force C/POSIX radix for scanf()-parsing (see bug 131831 ("Printing
 
711
   * does not work in de_AT@euro locale")), do the parsing and restore
 
712
   * the original locale.
 
713
   * XXX: This may affect all threads and not only the calling one...
 
714
   */
 
715
  {
 
716
#define CUR_LOCALE_SIZE 256
 
717
    char cur_locale[CUR_LOCALE_SIZE+1];
 
718
    strncpy(cur_locale, setlocale(LC_NUMERIC, NULL), CUR_LOCALE_SIZE);
 
719
    cur_locale[CUR_LOCALE_SIZE]='\0';
 
720
    setlocale(LC_NUMERIC, "C"); 
 
721
    num_input_items = sscanf(d, "%s %f %f %f %f", boolbuf, ma1, ma2, ma3, ma4);
 
722
    setlocale(LC_NUMERIC, cur_locale);
 
723
#undef CUR_LOCALE_SIZE
 
724
  }
 
725
 
 
726
  if( num_input_items != 5 )
 
727
  {
 
728
    free(name);
 
729
    return(False);
 
730
  }
 
731
 
 
732
  if( !strcmp(boolbuf, "true") )
 
733
    *mbool = True;
 
734
  else if( !strcmp(boolbuf, "false") )
 
735
    *mbool = False;
 
736
  else
 
737
  {
 
738
    free(name);
 
739
    return(False);    
 
740
  }
 
741
  return(True);
 
742
}
 
743
 
 
744
 
 
745
/* parse a paper size string 
 
746
 * (example: '{na-letter False {6.3500 209.5500 6.3500 273.0500}}') */
 
747
static
 
748
Bool XpuEnumerateMediumSourceSizes( Display *pdpy, XPContext pcontext,
 
749
                                    const char **tray_name,
 
750
                                    const char **medium_name, int *mbool, 
 
751
                                    float *ma1, float *ma2, float *ma3, float *ma4,
 
752
                                    void **vcptr )
 
753
{
 
754
  const char *medium_spec;
 
755
  const char *value = NULL;
 
756
  
 
757
  if( pdpy && pcontext )
 
758
  {
 
759
    value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "medium-source-sizes-supported");
 
760
    if( !value )
 
761
      return(False);
 
762
  }
 
763
 
 
764
  while(1)
 
765
  {  
 
766
    medium_spec = XpuEnumerateXpAttributeValue(value, vcptr);
 
767
    
 
768
    if( value )
 
769
    {
 
770
      XFree((void *)value);
 
771
      value = NULL;
 
772
    }
 
773
 
 
774
    /* enumeration done? */
 
775
    if( !medium_spec )
 
776
      return(False);
 
777
 
 
778
    if (XpuParseMediumSourceSize(medium_spec, 
 
779
                                 medium_name, mbool, 
 
780
                                 ma1, ma2, ma3, ma4))
 
781
    {
 
782
      *tray_name = XpuGetCurrentAttributeGroup(vcptr);
 
783
      return(True);
 
784
    }
 
785
    else
 
786
    {
 
787
      /* Should never ever happen! */
 
788
      fprintf(stderr, "XpuEnumerateMediumSourceSize: error parsing '%s'\n", medium_spec);
 
789
    }
 
790
  }
 
791
  /* not reached */   
 
792
}
 
793
 
 
794
static
 
795
void XpuDisposeEnumerateMediumSourceSizes( void **vc )
 
796
{
 
797
  XpuDisposeEnumerateXpAttributeValue(vc);
 
798
}  
 
799
 
 
800
 
 
801
/* future: Migrate this functionality into |XpGetPrinterList| - just do
 
802
 * not pass a |Display *| to |XpGetPrinterList|
 
803
 */
 
804
XPPrinterList XpuGetPrinterList( const char *printer, int *res_list_count )
 
805
{
 
806
  XPPrinterRec *rec = NULL;
 
807
  int           rec_count = 1; /* Allocate one more |XPPrinterRec| structure
 
808
                                * as terminator */
 
809
  char         *sl;
 
810
  const char   *default_printer_name = XpuGetDefaultXpPrintername();
 
811
  int           default_printer_rec_index = -1;
 
812
 
 
813
  if( !res_list_count )
 
814
    return(NULL); 
 
815
  
 
816
  sl = strdup(XpuGetXpServerList());
 
817
  MAKE_STRING_WRITABLE(printer);
 
818
    
 
819
  if( sl != NULL )
 
820
  {
 
821
    char *display;
 
822
    char *tok_lasts;
 
823
    
 
824
    for( display = strtok_r(sl, XPServerListSeparators, &tok_lasts) ; 
 
825
         display != NULL ; 
 
826
         display = strtok_r(NULL, XPServerListSeparators, &tok_lasts) )
 
827
    {
 
828
      Display *pdpy;
 
829
      
 
830
      if( (pdpy = XOpenDisplay(display)) != NULL )
 
831
      {
 
832
        XPPrinterList list;
 
833
        int           list_count;
 
834
        size_t        display_len = strlen(display);
 
835
 
 
836
        /* get list of available printers... */
 
837
        list = XpGetPrinterList(pdpy, STRING_AS_WRITABLE(printer), &list_count);        
 
838
      
 
839
        if( list && list_count )
 
840
        {
 
841
          int i;
 
842
          
 
843
          for( i = 0 ; i < list_count ; i++ )
 
844
          {
 
845
            char *s;
 
846
            
 
847
            /* Workaround for http://bugzilla.mozilla.org/show_bug.cgi?id=193499 
 
848
             * ("Xprint print/print preview crashes Mozilla") where the Solaris
 
849
             * Xprt may create invalid entries (e.g. |XpGetPrinterList| will
 
850
             * return |list[i].name==NULL| due to empty lines in the printer list.
 
851
             */
 
852
            if( !list[i].name )
 
853
              continue;
 
854
            
 
855
            rec_count++;
 
856
            rec = (XPPrinterRec *)realloc(rec, sizeof(XPPrinterRec)*rec_count);
 
857
            if( !rec ) /* failure */
 
858
              break;
 
859
              
 
860
            s = (char *)malloc(strlen(list[i].name)+display_len+4);
 
861
            sprintf(s, "%s@%s", list[i].name, display);
 
862
            rec[rec_count-2].name = s;
 
863
            rec[rec_count-2].desc = (list[i].desc)?(strdup(list[i].desc)):(NULL);
 
864
            
 
865
            /* Test for default printer (if the user set one).*/
 
866
            if( default_printer_name )
 
867
            {
 
868
              /* Default_printer_name may either contain the FQPN(=full
 
869
               * qualified printer name ("foo@myhost:5") or just the name
 
870
               * ("foo")) */
 
871
              if( (!strcmp(list[i].name, default_printer_name)) ||
 
872
                  (!strcmp(s,            default_printer_name)) )
 
873
              {
 
874
                /* Remember index of default printer that we can swap it to 
 
875
                 * the head of the array below... */
 
876
                default_printer_rec_index = rec_count-2;
 
877
              }
 
878
            }  
 
879
          }
 
880
          
 
881
          XpFreePrinterList(list);
 
882
        }
 
883
                 
 
884
        XCloseDisplay(pdpy);
 
885
      }
 
886
    }
 
887
    
 
888
    free(sl);
 
889
  }
 
890
  
 
891
  if( rec )
 
892
  {
 
893
    /* users: DO NOT COUNT ON THIS DETAIL 
 
894
     * (this is only to make current impl. of XpuFreePrinterList() easier)
 
895
     * I may remove this implementation detail in a later revision of
 
896
     * the library!
 
897
     */
 
898
    rec[rec_count-1].name = NULL;
 
899
    rec[rec_count-1].desc = NULL;
 
900
    rec_count--;
 
901
  }
 
902
  else
 
903
  {
 
904
    rec_count = 0;
 
905
  }
 
906
  
 
907
  /* The default printer is always the first one in the printer list... */
 
908
  if( (default_printer_rec_index != -1) && rec )
 
909
  {
 
910
    XPPrinterRec tmp;
 
911
    tmp = rec[0];
 
912
    rec[0] = rec[default_printer_rec_index];
 
913
    rec[default_printer_rec_index] = tmp;
 
914
  }
 
915
    
 
916
  *res_list_count = rec_count;
 
917
  FREE_WRITABLE_STRING(printer);
 
918
  return(rec);
 
919
}      
 
920
 
 
921
 
 
922
void XpuFreePrinterList( XPPrinterList list )
 
923
{
 
924
  if( list )
 
925
  {
 
926
    XPPrinterRec *curr = list;
 
927
  
 
928
    /* See the warning abouve about using this implementation detail for
 
929
     * checking for the list's end... */
 
930
    while( curr->name != NULL )
 
931
    {
 
932
      free(curr->name);
 
933
      if(curr->desc)
 
934
        free(curr->desc);
 
935
      curr++;
 
936
    }
 
937
  
 
938
    free(list);
 
939
  }
 
940
}
 
941
 
 
942
/* Set number of copies to print from this document */
 
943
int XpuSetDocumentCopies( Display *pdpy, XPContext pcontext, long num_copies )
 
944
{
 
945
  if( XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_COPY_COUNT)
 
946
  {
 
947
    XpuSetOneLongAttribute(pdpy, pcontext, XPDocAttr, "*copy-count", num_copies, XPAttrMerge);
 
948
    return(1);
 
949
  }
 
950
  else
 
951
  {
 
952
    XPU_DEBUG_ONLY(printf("XpuSetContentOrientation: XPUATTRIBUTESUPPORTED_COPY_COUNT not supported\n"));
 
953
       
 
954
    /* Failure... */
 
955
    return(0);
 
956
  }  
 
957
}
 
958
 
 
959
XpuMediumSourceSizeList XpuGetMediumSourceSizeList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
 
960
{
 
961
  XpuMediumSourceSizeList list = NULL;
 
962
  int                     rec_count = 1; /* allocate one more |XpuMediumSourceSizeRec| structure
 
963
                                          * as terminator */
 
964
  Bool                    status;
 
965
  float                   ma1,
 
966
                          ma2,
 
967
                          ma3,
 
968
                          ma4;
 
969
  char                   *value;
 
970
  void                   *tok_lasts;
 
971
  const char             *tray_name,
 
972
                         *medium_name;
 
973
  int                     mbool;
 
974
  const char             *default_tray,
 
975
                         *default_medium;
 
976
  int                     default_medium_rec_index = -1;
 
977
  
 
978
  default_tray   = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-input-tray");
 
979
  if(!default_tray)
 
980
  {
 
981
    fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-input-tray' found.\n");
 
982
    return(NULL);
 
983
  }
 
984
  default_medium = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "default-medium");
 
985
  if(!default_medium)
 
986
  {
 
987
    fprintf(stderr, "XpuGetMediumSourceSizeList: Internal error, no 'default-medium' found.\n");
 
988
    XFree((void *)default_tray);
 
989
    return(NULL);
 
990
  }
 
991
  
 
992
  for( status = XpuEnumerateMediumSourceSizes(pdpy, pcontext, &tray_name, &medium_name, &mbool,
 
993
                                              &ma1, &ma2, &ma3, &ma4, &tok_lasts) ;
 
994
       status != False ;
 
995
       status = XpuEnumerateMediumSourceSizes(NULL, None,     &tray_name, &medium_name, &mbool, 
 
996
                                              &ma1, &ma2, &ma3, &ma4, &tok_lasts) )
 
997
  {
 
998
    rec_count++;
 
999
    list = (XpuMediumSourceSizeRec *)realloc(list, sizeof(XpuMediumSourceSizeRec)*rec_count);
 
1000
    if( !list )
 
1001
      return(NULL);
 
1002
    
 
1003
    list[rec_count-2].tray_name   = (tray_name)?(strdup(tray_name)):(NULL);
 
1004
    list[rec_count-2].medium_name = strdup(medium_name);
 
1005
    list[rec_count-2].mbool       = mbool;
 
1006
    list[rec_count-2].ma1         = ma1;
 
1007
    list[rec_count-2].ma2         = ma2;
 
1008
    list[rec_count-2].ma3         = ma3;
 
1009
    list[rec_count-2].ma4         = ma4;
 
1010
    
 
1011
    /* Default medium ? */
 
1012
    if( (!strcmp(medium_name, default_medium)) && 
 
1013
        ((tray_name && (*default_tray))?(!strcmp(tray_name, default_tray)):(True)) )
 
1014
    {
 
1015
      default_medium_rec_index = rec_count-2;
 
1016
    }
 
1017
  }  
 
1018
 
 
1019
  XpuDisposeEnumerateMediumSourceSizes(&tok_lasts);
 
1020
 
 
1021
  if( list )
 
1022
  {
 
1023
    /* users: DO NOT COUNT ON THIS DETAIL 
 
1024
     * (this is only to make current impl. of XpuFreeMediumSourceSizeList() easier)
 
1025
     * I may remove this implementation detail in a later revision of
 
1026
     * the library! */
 
1027
    list[rec_count-1].tray_name  = NULL;
 
1028
    list[rec_count-1].medium_name = NULL;
 
1029
    rec_count--;
 
1030
  }
 
1031
  else
 
1032
  {
 
1033
    rec_count = 0;
 
1034
  }
 
1035
 
 
1036
  /* Make the default medium always the first item in the list... */
 
1037
  if( (default_medium_rec_index != -1) && list )
 
1038
  {
 
1039
    XpuMediumSourceSizeRec tmp;
 
1040
    tmp = list[0];
 
1041
    list[0] = list[default_medium_rec_index];
 
1042
    list[default_medium_rec_index] = tmp;
 
1043
  }
 
1044
 
 
1045
  *numEntriesPtr = rec_count; 
 
1046
  return(list);
 
1047
}
 
1048
 
 
1049
void XpuFreeMediumSourceSizeList( XpuMediumSourceSizeList list )
 
1050
{
 
1051
  if( list )
 
1052
  {
 
1053
    XpuMediumSourceSizeRec *curr = list;
 
1054
  
 
1055
    /* See the warning abouve about using this implementation detail for
 
1056
     * checking for the list's end... */
 
1057
    while( curr->medium_name != NULL )
 
1058
    {
 
1059
      if( curr->tray_name)
 
1060
        free((void *)curr->tray_name);
 
1061
      free((void *)curr->medium_name);
 
1062
      curr++;
 
1063
    }
 
1064
  
 
1065
    free(list);
 
1066
  }
 
1067
}
 
1068
 
 
1069
static
 
1070
int XpuSetMediumSourceSize( Display *pdpy, XPContext pcontext, XPAttributes type, XpuMediumSourceSizeRec *medium_spec )
 
1071
{
 
1072
  /* Set the "default-medium" and "*default-input-tray" 
 
1073
   * (if |XpuEnumerateMediumSourceSizes| returned one) XPDocAttr's
 
1074
   * attribute and return */
 
1075
  if (medium_spec->tray_name)
 
1076
  {
 
1077
    XpuSetOneAttribute(pdpy, pcontext, type, "*default-input-tray", medium_spec->tray_name, XPAttrMerge);
 
1078
  }
 
1079
  XpuSetOneAttribute(pdpy, pcontext, type, "*default-medium", medium_spec->medium_name, XPAttrMerge);
 
1080
  
 
1081
  return( 1 );
 
1082
}
 
1083
 
 
1084
/* Set document medium size */
 
1085
int XpuSetDocMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec )
 
1086
{
 
1087
  XpuSupportedFlags doc_supported_flags;
 
1088
  
 
1089
  doc_supported_flags = XpuGetSupportedDocAttributes(pdpy, pcontext);
 
1090
 
 
1091
  if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 )
 
1092
    return( 0 );
 
1093
    
 
1094
  if (medium_spec->tray_name)
 
1095
  {
 
1096
    if( (doc_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 )
 
1097
      return( 0 );  
 
1098
  }
 
1099
 
 
1100
  return XpuSetMediumSourceSize(pdpy, pcontext, XPDocAttr, medium_spec);
 
1101
}
 
1102
 
 
1103
/* Set page medium size */
 
1104
int XpuSetPageMediumSourceSize( Display *pdpy, XPContext pcontext, XpuMediumSourceSizeRec *medium_spec )
 
1105
{
 
1106
  XpuSupportedFlags page_supported_flags;
 
1107
  
 
1108
  page_supported_flags = XpuGetSupportedPageAttributes(pdpy, pcontext);
 
1109
 
 
1110
  if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM) == 0 )
 
1111
    return( 0 );
 
1112
    
 
1113
  if (medium_spec->tray_name)
 
1114
  {
 
1115
    if( (page_supported_flags & XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY) == 0 )
 
1116
      return( 0 );  
 
1117
  }
 
1118
 
 
1119
  return XpuSetMediumSourceSize(pdpy, pcontext, XPPageAttr, medium_spec);
 
1120
}
 
1121
 
 
1122
#ifndef ABS
 
1123
#define ABS(x) ((x)<0?-(x):(x))
 
1124
#endif /* ABS */
 
1125
#define MORE_OR_LESS_EQUAL(a, b, tolerance) (ABS((a) - (b)) <= (tolerance))
 
1126
 
 
1127
XpuMediumSourceSizeRec *
 
1128
XpuFindMediumSourceSizeBySize( XpuMediumSourceSizeList mlist, int mlist_count, 
 
1129
                               float page_width_mm, float page_height_mm, float tolerance )
 
1130
{
 
1131
  int i;
 
1132
  for( i = 0 ; i < mlist_count ; i++ )
 
1133
  {
 
1134
    XpuMediumSourceSizeRec *curr = &mlist[i];
 
1135
    float total_width  = curr->ma1 + curr->ma2,
 
1136
          total_height = curr->ma3 + curr->ma4;
 
1137
 
 
1138
    /* Match width/height*/
 
1139
    if( ((page_width_mm !=-1.f)?(MORE_OR_LESS_EQUAL(total_width,  page_width_mm,  tolerance)):(True)) &&
 
1140
        ((page_height_mm!=-1.f)?(MORE_OR_LESS_EQUAL(total_height, page_height_mm, tolerance)):(True)) )
 
1141
    {
 
1142
      return(curr);
 
1143
    }
 
1144
  }
 
1145
 
 
1146
  return(NULL);
 
1147
}
 
1148
 
 
1149
XpuMediumSourceSizeRec *
 
1150
XpuFindMediumSourceSizeByBounds( XpuMediumSourceSizeList mlist, int mlist_count, 
 
1151
                                 float m1, float m2, float m3, float m4, float tolerance )
 
1152
{
 
1153
  int i;
 
1154
  for( i = 0 ; i < mlist_count ; i++ )
 
1155
  {
 
1156
    XpuMediumSourceSizeRec *curr = &mlist[i];
 
1157
 
 
1158
    /* Match bounds */
 
1159
    if( ((m1!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma1, m1, tolerance)):(True)) &&
 
1160
        ((m2!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma2, m2, tolerance)):(True)) &&
 
1161
        ((m3!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma3, m3, tolerance)):(True)) &&
 
1162
        ((m4!=-1.f)?(MORE_OR_LESS_EQUAL(curr->ma4, m4, tolerance)):(True)) )
 
1163
    {
 
1164
      return(curr);
 
1165
    }
 
1166
  }
 
1167
 
 
1168
  return(NULL);
 
1169
}
 
1170
 
 
1171
XpuMediumSourceSizeRec *
 
1172
XpuFindMediumSourceSizeByName( XpuMediumSourceSizeList mlist, int mlist_count, 
 
1173
                               const char *tray_name, const char *medium_name )
 
1174
{
 
1175
  int i;
 
1176
  for( i = 0 ; i < mlist_count ; i++ )
 
1177
  {
 
1178
    XpuMediumSourceSizeRec *curr = &mlist[i];
 
1179
 
 
1180
    /* Match by tray name and/or medium name */
 
1181
    if( ((tray_name && curr->tray_name)?(!strcasecmp(curr->tray_name, tray_name)):(tray_name==NULL)) &&
 
1182
        ((medium_name)?(!strcasecmp(curr->medium_name, medium_name)):(True)) )
 
1183
    {
 
1184
      return(curr);
 
1185
    }
 
1186
  }
 
1187
 
 
1188
  return(NULL);
 
1189
}
 
1190
 
 
1191
XpuResolutionList XpuGetResolutionList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
 
1192
{
 
1193
  XpuResolutionList list = NULL;
 
1194
  int               rec_count = 1; /* Allocate one more |XpuResolutionRec| structure
 
1195
                                    * as terminator */
 
1196
  char             *value;
 
1197
  char             *tok_lasts;
 
1198
  const char       *s;
 
1199
  long              default_resolution = -1;
 
1200
  int               default_resolution_rec_index = -1;
 
1201
 
 
1202
  /* Get default document resolution */
 
1203
  if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", &default_resolution) != 1 )
 
1204
  {
 
1205
    default_resolution = -1;
 
1206
  }
 
1207
  
 
1208
  value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "printer-resolutions-supported");
 
1209
  if (!value)
 
1210
  {
 
1211
    fprintf(stderr, "XpuGetResolutionList: Internal error, no 'printer-resolutions-supported' XPPrinterAttr found.\n");
 
1212
    return(NULL);
 
1213
  }
 
1214
  
 
1215
  for( s = strtok_r(value, " ", &tok_lasts) ;
 
1216
       s != NULL ;
 
1217
       s = strtok_r(NULL, " ", &tok_lasts) )
 
1218
  {
 
1219
    long tmp;
 
1220
    
 
1221
    tmp = strtol(s, (char **)NULL, 10);
 
1222
    
 
1223
    if( ((tmp == 0L) || (tmp == LONG_MIN) || (tmp == LONG_MAX)) && 
 
1224
        ((errno == ERANGE) || (errno == EINVAL)) )
 
1225
    {
 
1226
      fprintf(stderr, "XpuGetResolutionList: Internal parser errror for '%s'.\n", s);
 
1227
      continue;
 
1228
    }    
 
1229
  
 
1230
    rec_count++;
 
1231
    list = (XpuResolutionRec *)realloc(list, sizeof(XpuResolutionRec)*rec_count);
 
1232
    if( !list )
 
1233
      return(NULL);
 
1234
    
 
1235
    list[rec_count-2].dpi = tmp;
 
1236
 
 
1237
    if( default_resolution != -1 )
 
1238
    {
 
1239
      /* Is this the default resolution ? */
 
1240
      if( list[rec_count-2].dpi == default_resolution )
 
1241
      {
 
1242
        default_resolution_rec_index = rec_count-2;
 
1243
      }
 
1244
    }  
 
1245
  }  
 
1246
 
 
1247
  XFree(value);
 
1248
 
 
1249
  if( list )
 
1250
  {
 
1251
    /* users: DO NOT COUNT ON THIS DETAIL 
 
1252
     * (this is only to make current impl. of XpuFreeMediumSourceSizeList() easier)
 
1253
     * I may remove this implementation detail in a later revision of
 
1254
     * the library! */
 
1255
    list[rec_count-1].dpi = -1;
 
1256
    rec_count--;
 
1257
  }
 
1258
  else
 
1259
  {
 
1260
    rec_count = 0;
 
1261
  }
 
1262
 
 
1263
  /* Make the default resolution always the first item in the list... */
 
1264
  if( (default_resolution_rec_index != -1) && list )
 
1265
  {
 
1266
    XpuResolutionRec tmp;
 
1267
    tmp = list[0];
 
1268
    list[0] = list[default_resolution_rec_index];
 
1269
    list[default_resolution_rec_index] = tmp;
 
1270
  }
 
1271
 
 
1272
  *numEntriesPtr = rec_count; 
 
1273
  return(list);
 
1274
}
 
1275
 
 
1276
void XpuFreeResolutionList( XpuResolutionList list )
 
1277
{
 
1278
  if( list )
 
1279
  { 
 
1280
    free(list);
 
1281
  }
 
1282
}
 
1283
 
 
1284
/* Find resolution in resolution list.
 
1285
 * Lower resolutions are preferred over larger resolution if |dpi_a| <= |dpi_b|,
 
1286
 * otherwise larger resolutions are preferred over small resolutions 
 
1287
 */
 
1288
XpuResolutionRec *XpuFindResolution( XpuResolutionList list, int list_count, long dpi_a, long dpi_b )
 
1289
{
 
1290
  XpuResolutionRec *match = NULL;
 
1291
  int               i;
 
1292
  
 
1293
  if( dpi_a <= dpi_b )
 
1294
  {
 
1295
    /* Search list, lower resolutions are better... */
 
1296
    for( i = 0 ; i < list_count ; i++ )
 
1297
    {
 
1298
      XpuResolutionRec *curr = &list[i];
 
1299
    
 
1300
      if( curr->dpi >= dpi_a && curr->dpi <= dpi_b )
 
1301
      {
 
1302
        if( !match || (curr->dpi < match->dpi) )
 
1303
        {
 
1304
          match = curr;
 
1305
        }
 
1306
      }
 
1307
    }
 
1308
  }
 
1309
  else
 
1310
  {
 
1311
    /* Search list, higher resolutions are better... */
 
1312
    for( i = 0 ; i < list_count ; i++ )
 
1313
    {
 
1314
      XpuResolutionRec *curr = &list[i];
 
1315
    
 
1316
      if( curr->dpi >= dpi_b && curr->dpi <= dpi_a )
 
1317
      {
 
1318
        if( !match || (curr->dpi > match->dpi) )
 
1319
        {
 
1320
          match = curr;
 
1321
        }
 
1322
      }
 
1323
    }
 
1324
  }
 
1325
 
 
1326
  return(match);
 
1327
}
 
1328
 
 
1329
/* Get default page (if defined) or document resolution
 
1330
 * this function may fail in the following conditions:
 
1331
 * - No default resolution set yet
 
1332
 * - X DPI != Y DPI (not yet implemented in Xprt)
 
1333
 */
 
1334
Bool XpuGetResolution( Display *pdpy, XPContext pcontext, long *dpi_ptr )
 
1335
{
 
1336
  /* Try to get the current page's resolution (pages may differ in resolution if the DDX supports this) */
 
1337
  if( XpuGetOneLongAttribute(pdpy, pcontext, XPPageAttr, "default-printer-resolution", dpi_ptr) == 1 )
 
1338
  {
 
1339
    return True;
 
1340
  }
 
1341
 
 
1342
  /* Get document resolution */
 
1343
  if( XpuGetOneLongAttribute(pdpy, pcontext, XPDocAttr, "default-printer-resolution", dpi_ptr) == 1 )
 
1344
  {
 
1345
    return True;
 
1346
  }
 
1347
 
 
1348
  return False;
 
1349
}
 
1350
 
 
1351
static
 
1352
int XpuSetResolution( Display *pdpy, XPContext pcontext, XPAttributes type, XpuResolutionRec *rec )
 
1353
{
 
1354
  XpuSetOneLongAttribute(pdpy, pcontext, type, "*default-printer-resolution", rec->dpi, XPAttrMerge); 
 
1355
  return( 1 );
 
1356
}
 
1357
 
 
1358
/* Set document resolution 
 
1359
 * Retun error if printer does not support setting a resolution
 
1360
 */
 
1361
int XpuSetDocResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec )
 
1362
{
 
1363
  if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 )
 
1364
    return( 0 );
 
1365
    
 
1366
  return XpuSetResolution(pdpy, pcontext, XPDocAttr, rec);
 
1367
}
 
1368
 
 
1369
/* Set page medium size 
 
1370
 * Retun error if printer does not support setting a resolution or if per-page
 
1371
 * resolution changes are not allowed.
 
1372
 */
 
1373
int XpuSetPageResolution( Display *pdpy, XPContext pcontext, XpuResolutionRec *rec )
 
1374
{
 
1375
  if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION) == 0 )
 
1376
    return( 0 );
 
1377
    
 
1378
  return XpuSetResolution(pdpy, pcontext, XPPageAttr, rec);
 
1379
}
 
1380
 
 
1381
XpuOrientationList XpuGetOrientationList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
 
1382
{
 
1383
  XpuOrientationList list = NULL;
 
1384
  int                rec_count = 1; /* Allocate one more |XpuOrientationRec|
 
1385
                                     * structure as terminator */
 
1386
  char              *value;
 
1387
  char              *tok_lasts;
 
1388
  const char        *s;
 
1389
  const char        *default_orientation = NULL;
 
1390
  int                default_orientation_rec_index = -1;
 
1391
 
 
1392
  /* Get default document orientation */
 
1393
  default_orientation = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "content-orientation"); 
 
1394
  if( !default_orientation )
 
1395
  {
 
1396
    fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientation' XPDocAttr found.\n");
 
1397
    return(NULL);
 
1398
  }
 
1399
  
 
1400
  value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "content-orientations-supported");
 
1401
  if (!value)
 
1402
  {
 
1403
    fprintf(stderr, "XpuGetOrientationList: Internal error, no 'content-orientations-supported' XPPrinterAttr found.\n");
 
1404
    return(NULL);
 
1405
  }
 
1406
  
 
1407
  for( s = strtok_r(value, " ", &tok_lasts) ;
 
1408
       s != NULL ;
 
1409
       s = strtok_r(NULL, " ", &tok_lasts) )
 
1410
  { 
 
1411
    rec_count++;
 
1412
    list = (XpuOrientationRec *)realloc(list, sizeof(XpuOrientationRec)*rec_count);
 
1413
    if( !list )
 
1414
      return(NULL);
 
1415
    
 
1416
    list[rec_count-2].orientation = strdup(s);
 
1417
 
 
1418
    /* Default resolution ? */
 
1419
    if( !strcmp(list[rec_count-2].orientation, default_orientation) )
 
1420
    {
 
1421
      default_orientation_rec_index = rec_count-2;
 
1422
    }
 
1423
  }  
 
1424
 
 
1425
  XFree(value);
 
1426
  XFree((void *)default_orientation);
 
1427
 
 
1428
  if( list )
 
1429
  {
 
1430
    /* users: DO NOT COUNT ON THIS DETAIL 
 
1431
     * (this is only to make current impl. of XpuFreeOrientationList() easier)
 
1432
     * I may remove this implementation detail in a later revision of
 
1433
     * the library! */
 
1434
    list[rec_count-1].orientation = NULL;
 
1435
    rec_count--;
 
1436
  }
 
1437
  else
 
1438
  {
 
1439
    rec_count = 0;
 
1440
  }
 
1441
 
 
1442
  /* Make the default orientation always the first item in the list... */
 
1443
  if( (default_orientation_rec_index != -1) && list )
 
1444
  {
 
1445
    XpuOrientationRec tmp;
 
1446
    tmp = list[0];
 
1447
    list[0] = list[default_orientation_rec_index];
 
1448
    list[default_orientation_rec_index] = tmp;
 
1449
  }
 
1450
 
 
1451
  *numEntriesPtr = rec_count; 
 
1452
  return(list);
 
1453
}
 
1454
 
 
1455
void XpuFreeOrientationList( XpuOrientationList list )
 
1456
{
 
1457
  if( list )
 
1458
  {
 
1459
    XpuOrientationRec *curr = list;
 
1460
  
 
1461
    /* See the warning abouve about using this implementation detail for
 
1462
     * checking for the list's end... */
 
1463
    while( curr->orientation != NULL )
 
1464
    {
 
1465
      free((void *)curr->orientation);
 
1466
      curr++;
 
1467
    }   
 
1468
    free(list);
 
1469
  }
 
1470
}
 
1471
 
 
1472
XpuOrientationRec *
 
1473
XpuFindOrientationByName( XpuOrientationList list, int list_count, const char *orientation )
 
1474
{
 
1475
  int i;
 
1476
  
 
1477
  for( i = 0 ; i < list_count ; i++ )
 
1478
  {
 
1479
    XpuOrientationRec *curr = &list[i];
 
1480
    if (!strcasecmp(curr->orientation, orientation))
 
1481
      return curr;
 
1482
  }
 
1483
 
 
1484
  return(NULL);
 
1485
}
 
1486
 
 
1487
static
 
1488
int XpuSetOrientation( Display *pdpy, XPContext pcontext, XPAttributes type, XpuOrientationRec *rec )
 
1489
{
 
1490
  XpuSetOneAttribute(pdpy, pcontext, type, "*content-orientation", rec->orientation, XPAttrMerge);
 
1491
  return(1);
 
1492
}
 
1493
 
 
1494
/* Set document orientation 
 
1495
 * Retun error if printer does not support setting an orientation
 
1496
 */
 
1497
int XpuSetDocOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec )
 
1498
{
 
1499
  if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 )
 
1500
    return( 0 );
 
1501
    
 
1502
  return XpuSetOrientation(pdpy, pcontext, XPDocAttr, rec);
 
1503
}
 
1504
 
 
1505
/* Set page orientation
 
1506
 * Retun error if printer does not support setting an orientation or if
 
1507
 * per-page orientations changes are not allowed
 
1508
 */
 
1509
int XpuSetPageOrientation( Display *pdpy, XPContext pcontext, XpuOrientationRec *rec )
 
1510
{
 
1511
  if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION) == 0 )
 
1512
    return( 0 );
 
1513
    
 
1514
  return XpuSetOrientation(pdpy, pcontext, XPPageAttr, rec);
 
1515
}
 
1516
 
 
1517
XpuPlexList XpuGetPlexList( Display *pdpy, XPContext pcontext, int *numEntriesPtr )
 
1518
{
 
1519
  XpuPlexList  list = NULL;
 
1520
  int          rec_count = 1; /* Allocate one more |XpuPlexList| structure
 
1521
                               * as terminator */
 
1522
  char        *value;
 
1523
  char        *tok_lasts;
 
1524
  const char  *s;
 
1525
  const char  *default_plex = NULL;
 
1526
  int          default_plex_rec_index = -1;
 
1527
 
 
1528
  /* Get default document plex */
 
1529
  default_plex = XpGetOneAttribute(pdpy, pcontext, XPDocAttr, "plex"); 
 
1530
  if( !default_plex )
 
1531
  {
 
1532
    fprintf(stderr, "XpuGetPlexList: Internal error, no 'plex' XPDocAttr found.\n");
 
1533
    return(NULL);
 
1534
  }
 
1535
   
 
1536
  value = XpGetOneAttribute(pdpy, pcontext, XPPrinterAttr, "plexes-supported");
 
1537
  if (!value)
 
1538
  {
 
1539
    fprintf(stderr, "XpuGetPlexList: Internal error, no 'plexes-supported' XPPrinterAttr found.\n");
 
1540
    return(NULL);
 
1541
  }
 
1542
  
 
1543
  for( s = strtok_r(value, " ", &tok_lasts) ;
 
1544
       s != NULL ;
 
1545
       s = strtok_r(NULL, " ", &tok_lasts) )
 
1546
  { 
 
1547
    rec_count++;
 
1548
    list = (XpuPlexRec *)realloc(list, sizeof(XpuPlexRec)*rec_count);
 
1549
    if( !list )
 
1550
      return(NULL);
 
1551
    
 
1552
    list[rec_count-2].plex = strdup(s);
 
1553
 
 
1554
    /* Default plex ? */
 
1555
    if( !strcmp(list[rec_count-2].plex, default_plex) )
 
1556
    {
 
1557
      default_plex_rec_index = rec_count-2;
 
1558
    }
 
1559
  }  
 
1560
 
 
1561
  XFree(value);
 
1562
  XFree((void *)default_plex);
 
1563
 
 
1564
  if( list )
 
1565
  {
 
1566
    /* users: DO NOT COUNT ON THIS DETAIL 
 
1567
     * (this is only to make current impl. of XpuFreePlexList() easier)
 
1568
     * I may remove this implementation detail in a later revision of
 
1569
     * the library! */
 
1570
    list[rec_count-1].plex = NULL;
 
1571
    rec_count--;
 
1572
  }
 
1573
  else
 
1574
  {
 
1575
    rec_count = 0;
 
1576
  }
 
1577
 
 
1578
  /* Make the default plex always the first item in the list... */
 
1579
  if( (default_plex_rec_index != -1) && list )
 
1580
  {
 
1581
    XpuPlexRec tmp;
 
1582
    tmp = list[0];
 
1583
    list[0] = list[default_plex_rec_index];
 
1584
    list[default_plex_rec_index] = tmp;
 
1585
  }
 
1586
 
 
1587
  *numEntriesPtr = rec_count; 
 
1588
  return(list);
 
1589
}
 
1590
 
 
1591
void XpuFreePlexList( XpuPlexList list )
 
1592
{
 
1593
  if( list )
 
1594
  {
 
1595
    XpuPlexRec *curr = list;
 
1596
  
 
1597
    /* See the warning abouve about using this implementation detail for
 
1598
     * checking for the list's end... */
 
1599
    while( curr->plex != NULL )
 
1600
    {
 
1601
      free((void *)curr->plex);
 
1602
      curr++;
 
1603
    }   
 
1604
    free(list);
 
1605
  }
 
1606
}
 
1607
 
 
1608
XpuPlexRec *
 
1609
XpuFindPlexByName( XpuPlexList list, int list_count, const char *plex )
 
1610
{
 
1611
  int i;
 
1612
  
 
1613
  for( i = 0 ; i < list_count ; i++ )
 
1614
  {
 
1615
    XpuPlexRec *curr = &list[i];
 
1616
    if (!strcasecmp(curr->plex, plex))
 
1617
      return curr;
 
1618
  }
 
1619
 
 
1620
  return(NULL);
 
1621
}
 
1622
 
 
1623
static
 
1624
int XpuSetContentPlex( Display *pdpy, XPContext pcontext, XPAttributes type, XpuPlexRec *rec )
 
1625
{
 
1626
  XpuSetOneAttribute(pdpy, pcontext, type, "*plex", rec->plex, XPAttrMerge);
 
1627
  return(1);
 
1628
}
 
1629
 
 
1630
/* Set document plex 
 
1631
 * Retun error if printer does not support setting an plex
 
1632
 */
 
1633
int XpuSetDocPlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec )
 
1634
{
 
1635
  if( (XpuGetSupportedDocAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 )
 
1636
    return( 0 );
 
1637
    
 
1638
  return XpuSetContentPlex(pdpy, pcontext, XPDocAttr, rec);
 
1639
}
 
1640
 
 
1641
/* Set page plex
 
1642
 * Retun error if printer does not support setting an plex or if
 
1643
 * per-page plex changes are not allowed
 
1644
 */
 
1645
int XpuSetPagePlex( Display *pdpy, XPContext pcontext, XpuPlexRec *rec )
 
1646
{
 
1647
  if( (XpuGetSupportedPageAttributes(pdpy, pcontext) & XPUATTRIBUTESUPPORTED_PLEX) == 0 )
 
1648
    return( 0 );
 
1649
    
 
1650
  return XpuSetContentPlex(pdpy, pcontext, XPPageAttr, rec);
 
1651
}
 
1652
 
 
1653
 
 
1654
/* Return flags to indicate which attributes are supported and which not... */
 
1655
static
 
1656
XpuSupportedFlags XpuGetSupportedAttributes( Display *pdpy, XPContext pcontext, XPAttributes type, const char *attribute_name )
 
1657
{
 
1658
  char              *value;
 
1659
  void              *tok_lasts;
 
1660
  XpuSupportedFlags  flags = 0;
 
1661
  
 
1662
  MAKE_STRING_WRITABLE(attribute_name);
 
1663
  if( attribute_name == NULL )
 
1664
    return(0);
 
1665
    
 
1666
  value = XpGetOneAttribute(pdpy, pcontext, type, STRING_AS_WRITABLE(attribute_name));   
 
1667
  
 
1668
  FREE_WRITABLE_STRING(attribute_name);
 
1669
  
 
1670
  if( value != NULL )
 
1671
  {
 
1672
    const char *s;
 
1673
    
 
1674
    for( s = XpuEnumerateXpAttributeValue(value, &tok_lasts) ; s != NULL ; s = XpuEnumerateXpAttributeValue(NULL, &tok_lasts) )
 
1675
    {
 
1676
           if( !strcmp(s, "job-name") )                   flags |= XPUATTRIBUTESUPPORTED_JOB_NAME;
 
1677
      else if( !strcmp(s, "job-owner") )                  flags |= XPUATTRIBUTESUPPORTED_JOB_OWNER;
 
1678
      else if( !strcmp(s, "notification-profile") )       flags |= XPUATTRIBUTESUPPORTED_NOTIFICATION_PROFILE;
 
1679
      else if( !strcmp(s, "copy-count") )                 flags |= XPUATTRIBUTESUPPORTED_COPY_COUNT;
 
1680
      else if( !strcmp(s, "document-format") )            flags |= XPUATTRIBUTESUPPORTED_DOCUMENT_FORMAT;
 
1681
      else if( !strcmp(s, "content-orientation") )        flags |= XPUATTRIBUTESUPPORTED_CONTENT_ORIENTATION;
 
1682
      else if( !strcmp(s, "default-printer-resolution") ) flags |= XPUATTRIBUTESUPPORTED_DEFAULT_PRINTER_RESOLUTION;
 
1683
      else if( !strcmp(s, "default-input-tray") )         flags |= XPUATTRIBUTESUPPORTED_DEFAULT_INPUT_TRAY;
 
1684
      else if( !strcmp(s, "default-medium") )             flags |= XPUATTRIBUTESUPPORTED_DEFAULT_MEDIUM;
 
1685
      else if( !strcmp(s, "plex") )                       flags |= XPUATTRIBUTESUPPORTED_PLEX;
 
1686
    }
 
1687
    
 
1688
    XpuDisposeEnumerateXpAttributeValue(&tok_lasts);
 
1689
    XFree(value);
 
1690
  }  
 
1691
  
 
1692
  return(flags);
 
1693
}
 
1694
 
 
1695
XpuSupportedFlags XpuGetSupportedJobAttributes(Display *pdpy, XPContext pcontext)
 
1696
{
 
1697
  return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "job-attributes-supported");
 
1698
}
 
1699
 
 
1700
XpuSupportedFlags XpuGetSupportedDocAttributes(Display *pdpy, XPContext pcontext)
 
1701
{
 
1702
  return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "document-attributes-supported");
 
1703
}
 
1704
 
 
1705
XpuSupportedFlags XpuGetSupportedPageAttributes(Display *pdpy, XPContext pcontext)
 
1706
{
 
1707
  return XpuGetSupportedAttributes(pdpy, pcontext, XPPrinterAttr, "xp-page-attributes-supported");
 
1708
}
 
1709
 
 
1710
/* EOF. */