File indexing completed on 2024-04-21 15:12:17

0001 /************************************************************************/
0002 /*                                  */
0003 /*  This file is part of the KDE Project                */
0004 /*  Copyright (c) 2004 Jonathan Marten <jjm@keelhaul.me.uk>     */
0005 /*                                  */
0006 /*  This program is free software; you can redistribute it and/or   */
0007 /*  modify it under the terms of the GNU General Public License as  */
0008 /*  published by the Free Software Foundation; either version 2 of  */
0009 /*  the License, or (at your option) any later version.         */
0010 /*                                  */
0011 /*  It is distributed in the hope that it will be useful, but       */
0012 /*  WITHOUT ANY WARRANTY; without even the implied warranty of      */
0013 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   */
0014 /*  GNU General Public License for more details.            */
0015 /*                                  */
0016 /*  You should have received a copy of the GNU General Public       */
0017 /*  License along with this program; see the file COPYING for further   */
0018 /*  details.  If not, write to the Free Software Foundation, Inc.,  */
0019 /*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.    */
0020 /*                                  */
0021 /************************************************************************/
0022 
0023 
0024 /************************************************************************/
0025 /*  Include files                           */
0026 /************************************************************************/
0027 
0028 #include <stdio.h>                  /* Standard I/O library */
0029 #include <unistd.h>                 /* Unix(TM) system routines */
0030 #include <string.h>                 /* String handling routines */
0031 #include <stdarg.h>                 /* Variable parameter handling */
0032 #include <errno.h>                  /* Library error numbers */
0033 #include <stdlib.h>                 /* Standard library routines */
0034 
0035 #include <sane/sane.h>                  /* SANE scanner access */
0036 
0037 /************************************************************************/
0038 /*  Global variables                            */
0039 /************************************************************************/
0040 
0041 const char *myname;                 /* my program name */
0042 
0043 static int listmode = 0;                /* option 'L' -> probe and list */
0044 static char devname[256] = "";              /* option 'd' -> device name */
0045 static int longdesc = 0;                /* option 'l' -> long descriptions */
0046 static int advopt = 0;                  /* option 'a' -> advanced options */
0047 
0048 SANE_Status sanerr;                 /* SANE error status */
0049 
0050 static const char *fmt = "%-14s  ";         /* format for output */
0051 
0052 /************************************************************************/
0053 /*  Message keys for cmderr() - sync with 'errstrings'          */
0054 /************************************************************************/
0055 
0056 enum cemsg
0057 {
0058     CEERROR     = 0,                /* exit */
0059     CENONE      = 1,                /* benign */
0060     CEWARNING   = 2,                /* continue */
0061     CENOTICE    = 3,                /* continue */
0062     CEINFO      = 4,                /* continue */
0063     CESUCCESS   = 5,                /* continue */
0064     CEFATAL     = 6,                /* exit */
0065     CEUNKNOWN   = 7             /* must be last */
0066 };
0067 
0068 /************************************************************************/
0069 /*  Error source keys for cmderr()                  */
0070 /************************************************************************/
0071 
0072 enum cesys
0073 {
0074     CSNONE      = 0,                /* no message */
0075     CSERRNO     = 1,                /* decode 'errno' */
0076     CSSANE      = 2             /* decode SANE status */
0077 };
0078 
0079 /************************************************************************/
0080 /*  Severity strings for cmderr() reports               */
0081 /************************************************************************/
0082 
0083 static const char *errstrings[] =
0084 {
0085     "ERROR",                        /* 0 */
0086     NULL,                       /* 1 */
0087     "WARNING",                      /* 2 */
0088     "NOTICE",                       /* 3 */
0089     "INFO",                     /* 4 */
0090     "SUCCESS",                      /* 5 */
0091     "FATAL",                        /* 6 */
0092     NULL                        /* 7 */
0093 };
0094 
0095 /************************************************************************/
0096 /*  cmderr -- Display an error message with parameters, optionally  */
0097 /*  adding the system or SANE error as well.                */
0098 /************************************************************************/
0099 
0100 void 
0101 #if defined(__GNUC__)
0102 __attribute__((format (printf,3,4)))
0103 #endif
0104 cmderr(enum cesys src,enum cemsg sev,const char *fmtstr,...)
0105 {
0106     va_list args;                   /* parameters for format */
0107     const char *ss;                 /* severity string */
0108     const char *mm = NULL;              /* textual error message*/
0109 
0110     if (src==CSERRNO) mm = strerror(errno);     /* system error message */
0111     else if (src==CSSANE) mm = sane_strstatus(sanerr);  /* SANE error message */
0112 
0113     fflush(stdout); fflush(stderr);         /* flush current output */
0114                             /* catch bad parameter */
0115     if (((int) sev)<0 || sev>CEUNKNOWN) sev = CEUNKNOWN;
0116     ss = errstrings[sev];
0117 
0118     fprintf(stderr,"%s",myname);            /* report our program name */
0119     if (ss!=NULL) fprintf(stderr," (%s)",ss);       /* report severity if there is one */
0120     fprintf(stderr,": ");
0121 
0122     va_start(args,fmtstr);              /* locate variable parameters */
0123     vfprintf(stderr,fmtstr,args);           /* user message and parameters */
0124     if (mm!=NULL) fprintf(stderr,", %s",mm);        /* system error message */
0125     va_end(args);                   /* finished with parameters */
0126     fprintf(stderr,"\n");               /* end of message */
0127                             /* exit from application */
0128     if (sev==CEERROR || sev==CEFATAL) exit(EXIT_FAILURE);
0129 }
0130 
0131 /************************************************************************/
0132 /*  usage -- Display the command line and option help.          */
0133 /************************************************************************/
0134 
0135 void usage()
0136 {
0137     fprintf(stderr,"Usage:    %s -L                  probe and list scanner devices\n",myname);
0138     fprintf(stderr,"          %s [-la] [-d] device   display information for scanner device\n",myname);
0139     fprintf(stderr,"\n");
0140     fprintf(stderr,"Options:  -d     specify SANE device (backend) name\n");
0141     fprintf(stderr,"          -l     display long SANE option description\n");
0142     fprintf(stderr,"          -a     display advanced SANE options\n");
0143     exit(2);
0144 }
0145 
0146 /************************************************************************/
0147 /*  do_init - Initialise SANE and report its version.           */
0148 /************************************************************************/
0149 
0150 void do_init()
0151 {
0152     SANE_Int sanevers;
0153 
0154     sanerr = sane_init(&sanevers,NULL);
0155     if (sanerr!=SANE_STATUS_GOOD) cmderr(CSSANE,CEFATAL,"cannot initialise SANE");
0156     printf(fmt,"SANE version:");
0157     printf("%d.%d.%d\n",SANE_VERSION_MAJOR(sanevers),
0158            SANE_VERSION_MINOR(sanevers),SANE_VERSION_BUILD(sanevers));
0159 }
0160 
0161 /************************************************************************/
0162 /*  do_listmode -- List all SANE devices known.             */
0163 /************************************************************************/
0164 
0165 void do_listmode()
0166 {
0167     const SANE_Device **devlist;
0168     const SANE_Device *dev;
0169     int i;
0170 
0171     do_init();
0172 
0173     sanerr = sane_get_devices(&devlist,SANE_FALSE); /* local and network */
0174     if (sanerr!=SANE_STATUS_GOOD) cmderr(CSSANE,CEFATAL,"SANE cannot get device list");
0175 
0176     printf("\n");
0177     for (i = 0; devlist[i]!=NULL; ++i)
0178     {
0179         dev = devlist[i];
0180 
0181         printf(fmt,"Device:",dev->name);
0182         printf(fmt,"Vendor:",dev->vendor);
0183         printf(fmt,"Model:",dev->model);
0184         printf(fmt,"Type:",dev->type);
0185         printf("\n");
0186     }
0187 
0188     if (i==0)
0189     {
0190         cmderr(CSNONE,CENOTICE,"No devices found");
0191         cmderr(CSNONE,CEINFO,"Try sane-find-scanner(1), or hp-probe(1) for HP devices");
0192     }
0193 }
0194 
0195 /************************************************************************/
0196 /*  do_describe -- Given a SANE device, decode and display all of its   */
0197 /*  option descriptors.                         */
0198 /************************************************************************/
0199 
0200 void do_describe(const char *dev)
0201 {
0202     SANE_Handle hand;
0203     const SANE_Option_Descriptor *desc;
0204     SANE_Int numopt;
0205     int opt;
0206     double min,max,q;
0207     const SANE_String_Const *sp;
0208     const SANE_Word *wp;
0209     int nw;
0210     int i;
0211 
0212 
0213     do_init();
0214 
0215     sanerr = sane_open(dev,&hand);
0216     if (sanerr!=SANE_STATUS_GOOD) cmderr(CSSANE,CEFATAL,"SANE cannot open '%s'",dev);
0217 
0218     /* get option index 0 = number of options */
0219     sanerr = sane_control_option(hand,0,SANE_ACTION_GET_VALUE,&numopt,NULL);
0220     if (sanerr!=SANE_STATUS_GOOD) cmderr(CSSANE,CEFATAL,"SANE cannot get option 0");
0221 
0222     printf(fmt,"Found:");
0223     printf("%d options\n",numopt);
0224 
0225     for (opt = 1; opt<numopt; ++opt)
0226     {
0227         desc = sane_get_option_descriptor(hand,opt);
0228         if (desc==NULL)
0229         {
0230             cmderr(CSNONE,CEWARNING,"SANE option %d is not valid",opt);
0231             continue;
0232         }
0233 
0234         if (!advopt && (desc->cap & SANE_CAP_ADVANCED)) continue;
0235 
0236         printf("\n");
0237         printf(fmt,"Option:");
0238         printf("%d\n",opt);
0239 
0240         if (desc->name!=NULL && desc->name[0]!='\0')
0241         {
0242             printf(fmt,"Name:");
0243             printf("%s\n",desc->name);
0244         }
0245 
0246         if (desc->title!=NULL)
0247         {
0248             printf(fmt,"Title:");
0249             printf("\"%s\"\n",desc->title);
0250         }
0251 
0252         if (desc->desc!=NULL && desc->desc[0]!='\0' && longdesc)
0253         {
0254             printf(fmt,"Description:");
0255             printf("\"%s\"\n",desc->desc);
0256         }
0257 
0258         printf(fmt,"Value type:");
0259         switch (desc->type)
0260         {
0261 case SANE_TYPE_BOOL:    printf("BOOL");         break;
0262 case SANE_TYPE_INT: printf("INT");          break;
0263 case SANE_TYPE_FIXED:   printf("FIXED");        break;
0264 case SANE_TYPE_STRING:  printf("STRING");       break;
0265 case SANE_TYPE_BUTTON:  printf("BUTTON");       break;
0266 case SANE_TYPE_GROUP:   printf("GROUP");        break;
0267 default:        printf("%d",desc->type);    break;
0268         }
0269         printf("\n");
0270 
0271         if (desc->unit!=SANE_UNIT_NONE)
0272         {
0273             printf(fmt,"Unit:");
0274             switch (desc->unit)
0275             {
0276 case SANE_UNIT_NONE:        printf("NONE");         break;
0277 case SANE_UNIT_PIXEL:       printf("PIXELS");       break;
0278 case SANE_UNIT_BIT:     printf("BITS");         break;
0279 case SANE_UNIT_MM:      printf("MM");           break;
0280 case SANE_UNIT_DPI:     printf("DPI");          break;
0281 case SANE_UNIT_PERCENT:     printf("PERCENT");      break;
0282 case SANE_UNIT_MICROSECOND: printf("MICROSECOND");      break;
0283 default:            printf("%d",desc->unit);    break;
0284             }
0285             printf("\n");
0286         }
0287 
0288         if (desc->cap!=0)
0289         {
0290             printf(fmt,"Capabilities:");
0291             if (desc->cap & SANE_CAP_SOFT_SELECT) printf("SOFT_SELECT ");
0292             if (desc->cap & SANE_CAP_HARD_SELECT) printf("HARD_SELECT ");
0293             if (desc->cap & SANE_CAP_SOFT_DETECT) printf("SOFT_DETECT ");
0294             if (desc->cap & SANE_CAP_EMULATED) printf("EMULATED ");
0295             if (desc->cap & SANE_CAP_AUTOMATIC) printf("AUTOMATIC ");
0296             if (desc->cap & SANE_CAP_INACTIVE) printf("INACTIVE ");
0297             if (desc->cap & SANE_CAP_ADVANCED) printf("ADVANCED ");
0298 #ifdef SANE_CAP_ALWAYS_SETTABLE
0299             if (desc->cap & SANE_CAP_ALWAYS_SETTABLE) printf("ALWAYS_SETTABLE ");
0300 #endif
0301             printf("\n");
0302         }
0303 
0304         if (desc->constraint_type!=SANE_CONSTRAINT_NONE)
0305         {
0306             printf(fmt,"Constraint:");
0307             switch (desc->constraint_type)
0308             {
0309 case SANE_CONSTRAINT_NONE:  printf("NONE");
0310                 break;
0311 
0312 case SANE_CONSTRAINT_RANGE: switch (desc->type)
0313                 {
0314 case SANE_TYPE_INT:         min = desc->constraint.range->min;
0315                     max = desc->constraint.range->max;
0316                     q = desc->constraint.range->quant;
0317                     break;
0318 
0319 case SANE_TYPE_FIXED:           min = SANE_UNFIX(desc->constraint.range->min);
0320                     max = SANE_UNFIX(desc->constraint.range->max);
0321                     q = SANE_UNFIX(desc->constraint.range->quant);
0322                     break;
0323 
0324 default:                min = max = q = 0;
0325                     break;
0326                 }
0327 
0328                 if (q==0) q = 1.0;
0329                 if (q==1.0)
0330                 {
0331                     printf("RANGE %g - %g",min,max);
0332                 }
0333                 else
0334                 {
0335                     printf("RANGE %g - %g by %g = %g - %g",
0336                            min,max,q,min/q,max/q);
0337                 }
0338                 break;
0339 
0340 case SANE_CONSTRAINT_STRING_LIST:
0341                 printf("STRING_LIST [");
0342                 for (sp = desc->constraint.string_list; *sp!=NULL; ++sp)
0343                 {
0344                     printf("\"%s\"",*sp);
0345                     if (sp[1]!=NULL) printf(" ");
0346                 }
0347                 printf("]");
0348                 break;
0349 
0350 case SANE_CONSTRAINT_WORD_LIST:
0351                 printf("WORD_LIST ");
0352                 wp = desc->constraint.word_list;
0353                 nw = *wp++;
0354                 printf("%d [",nw);
0355                 for (i = 0; i<nw; ++i)
0356                 {
0357                     if (desc->type==SANE_TYPE_FIXED) printf("%g",SANE_UNFIX(*wp));
0358                     else printf("%d",*wp);
0359                     ++wp;
0360                     if ((i+1)!=nw) printf(" ");
0361                 }
0362                 printf("]");
0363                 break;
0364 
0365 default:            printf("%d",desc->constraint_type);
0366                 break;
0367             }
0368 
0369             printf("\n");
0370         }
0371 
0372         if (desc->size>0 && desc->size!=sizeof(SANE_Word))
0373         {
0374             printf(fmt,"Data size:");
0375             printf("%d\n",desc->size);
0376         }
0377     }
0378 
0379     printf("\n");
0380     sane_close(hand);
0381     sane_exit();
0382 }
0383 
0384 /************************************************************************/
0385 /*  Main -- Handle command line and options             */
0386 /************************************************************************/
0387 
0388 int main(int argc, char **argv)
0389 {
0390     int opt;
0391     int i;
0392 
0393     myname = strrchr(argv[0],'/');          /* extract our program name */
0394     if (myname==NULL) myname = argv[0];
0395     else ++myname;
0396 
0397     while ((opt = getopt(argc,argv,":halLd:"))!=-1)
0398     {
0399         switch (opt)
0400         {
0401 case 'L':       listmode = 1;           /* probe and list devices */
0402             break;
0403 
0404 case 'd':       strcpy(devname,optarg);     /* specify device name */
0405             break;
0406 
0407 case 'l':       longdesc = 1;           /* show long descriptions */
0408             break;
0409 
0410 case 'a':       advopt = 1;         /* show advanced options */
0411             break;
0412 
0413 case 'h':       usage();            /* display help */
0414             break;
0415 
0416 default:
0417 case '?':       cmderr(CSNONE,CEERROR,"Unrecognised option '%c' (use '-h' for help)",optopt);
0418             break;
0419 
0420 case ':':       cmderr(CSNONE,CEERROR,"Option '%c' requires an argument (use '-h' for help)",optopt);
0421             break;
0422         }
0423     }
0424 
0425     argc -= optind;                 /* adjust for parsed options */
0426     argv += optind;
0427 
0428     if (listmode)
0429     {
0430         if (longdesc || advopt) cmderr(CSNONE,CEWARNING,"Options '-l'/-a' igored in listing mode ('-L')");
0431     }
0432 
0433     if (devname[0]=='\0')
0434     {
0435         if (!listmode)
0436         {
0437             if (argc==0) cmderr(CSNONE,CEERROR,"No options or devices specified (use '-h' for help)");
0438             for (i = 0; argv[i]!=NULL; ++i) do_describe(argv[i]);
0439         }
0440         else
0441         {
0442             if (argc>0) cmderr(CSNONE,CEWARNING,"Arguments ignored for listing mode ('-L')");
0443             do_listmode();
0444         }
0445     }
0446     else
0447     {
0448         if (listmode) cmderr(CSNONE,CEERROR,"Only one of the '-d'/'-L' options may be specified");
0449         if (argc>0) cmderr(CSNONE,CEWARNING,"Additional arguments with '-d' ignored");
0450         do_describe(devname);
0451     }
0452 
0453     return (EXIT_SUCCESS);
0454 }