1 /* @source ajmess *************************************************************
2 **
3 ** AJAX message functions
4 **
5 ** @author Richard Durbin and Ed Griffiths from ACEdb (messubs.c)
6 ** @version $Revision: 1.56 $
7 ** @modified Ian Longden for EMBOSS
8 ** @modified $Date: 2012/12/07 09:54:19 $ by $Author: rice $
9 ** @@
10 **
11 ** This library is free software; you can redistribute it and/or
12 ** modify it under the terms of the GNU Lesser General Public
13 ** License as published by the Free Software Foundation; either
14 ** version 2.1 of the License, or (at your option) any later version.
15 **
16 ** This library is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ** Lesser General Public License for more details.
20 **
21 ** You should have received a copy of the GNU Lesser General Public
22 ** License along with this library; if not, write to the Free Software
23 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 ** MA 02110-1301, USA.
25 **
26 ******************************************************************************/
27
28 #include <string.h>
29
30 #include <errno.h>
31 #include <limits.h>
32 #include <stdlib.h>
33
34 #include "ajmess.h"
35 #include "ajassert.h"
36 #include "ajmem.h"
37 #include "ajtable.h"
38 #include "ajfmt.h"
39 #include "ajsys.h"
40 #include "ajfile.h"
41 #include "ajutil.h"
42 #include "ajnam.h"
43 #include "ajfileio.h"
44
45 #ifdef __CYGWIN__
46 #define fopen(a,b) ajSysFuncFopen(a,b)
47 #endif
48
49
50 /* next six moved from acd for library splitting */
51
52 AjBool acdDebugSet = 0;
53 AjBool acdDebugBuffer = 0;
54 AjBool acdDebug = 0;
55 AjPStr acdProgram = NULL;
56 AjPStr acdAppldoc = NULL;
57 AjPStr acdArgSave = NULL;
58 AjPStr acdInputSave = NULL;
59
60
61
62 AjOError AjErrorLevel =
63 {
64 AJTRUE, AJTRUE, AJTRUE, AJTRUE
65 };
66
67 /***************************************************/
68
69
70
71 AjPTable messErrorTable = 0;
72
73 static ajint errorCount = 0;
74
75 static char *messErrorFile;
76
77 static AjBool messDebug = 0;
78 static AjPFile messDebugFile = NULL;
79 static AjPFile messDebugTestFile = NULL;
80 static AjPStr messDebugName = NULL;
81 static char* messErrMess = NULL;
82 static AjBool messDebugTestInit = AJFALSE;
83
84 static char* messGetFilename(const char *path);
85 static void messTableDelete(AjPTable* table);
86
87 static AjPTable messDebugTestTable = NULL;
88
89
90 /*============================================================================
91 **======================== Macros ============================================
92 =============================================================================*/
93
94
95
96
97 /* @macro ajFatal *************************************************************
98 **
99 ** Fatal error message to standard error.
100 ** Includes filename and line number in the source code that invokes it.
101 ** Newline is added automatically at the end of the format string.
102 **
103 ** @param [r] format [const char*] Format
104 ** @param [v] [...] Variable length argument list
105 ** @return [void]
106 ** @@
107 ******************************************************************************/
108
109
110
111
112 /* @macro ajMessCrash *********************************************************
113 **
114 ** Crash error message to standard error.
115 ** Includes filename and line number in the source code that invokes it.
116 ** Newline is added automatically at the end of the format string.
117 **
118 ** @param [r] format [const char*] Format
119 ** @param [v] [...] Variable length argument list
120 ** @return [void]
121 ** @@
122 ******************************************************************************/
123
124
125
126
127 /* @func ajMessInvokeDebugger *************************************************
128 **
129 ** Used to trace in a debugger as a breakpoint
130 **
131 ** @return [void]
132 **
133 ** @release 1.0.0
134 ** @@
135 ******************************************************************************/
136
ajMessInvokeDebugger(void)137 void ajMessInvokeDebugger(void)
138 {
139 static AjBool reentrant = AJFALSE;
140
141 if(!reentrant)
142 {
143 reentrant = AJTRUE;
144 reentrant = AJFALSE;
145 }
146
147 return;
148 }
149
150
151
152
153 /******************************************************************************
154 ** Constraints on message buffer size.
155 **
156 ** BUFSIZE: size of message buffers (messbuf, a global buffer for general
157 ** message stuff and a private one in ajMessDump).
158 ** PREFIX: length of message prefix (used to report details such as the
159 ** file/line info. for where the error occurred.
160 ** MAINTEXT: space left in buffer is the rest after the prefix and string
161 ** terminator (NULL) are subtracted.
162 ******************************************************************************/
163
164 enum {BUFSIZE = 32768,
165 PREFIXSIZE = 1024,
166 MAINTEXTSIZE = BUFSIZE - PREFIXSIZE - 1};
167
168 /******************************************************************************
169 ** This buffer is used by just about all of the below routines and has the
170 ** obvious problem that strings can run over the end of it, we can only
171 ** detect this after the event with vsprintf.
172 ******************************************************************************/
173
174 static char messbuf[BUFSIZE];
175
176 /******************************************************************************
177 ** Format strings using va_xx calls.
178 ** Arguments to the macro must have the following types:
179 ** FORMAT_ARGS: va_list used to get the variable argument list.
180 ** FORMAT: char * to a string containing the printf format string.
181 ** TARGET_PTR: char * the formatted string will be returned in this
182 ** string pointer, N.B. do not put &TARGET_PTR
183 ** PREFIX: char * to a string to be used as a prefix to the rest
184 ** of the string, or NULL.
185 ******************************************************************************/
186
187 #define AJAXFORMATSTRING(FORMAT_ARGS, FORMAT, TARGET_PTR, PREFIX) \
188 va_start(FORMAT_ARGS, FORMAT); \
189 TARGET_PTR = messFormat(FORMAT_ARGS, FORMAT, PREFIX); \
190 va_end(FORMAT_ARGS);
191
192 #define AJAXVFORMATSTRING(FORMAT_ARGS, FORMAT, TARGET_PTR, PREFIX) \
193 TARGET_PTR = messFormat(FORMAT_ARGS, FORMAT, PREFIX);
194
195 static char *messFormat(va_list args, const char *format, const char *prefix);
196 static void messDump(const char *message);
197
198 /* Some standard defines for titles/text for messages: */
199 /* */
200
201 #define MESG_TITLE "EMBOSS"
202 #define ERROR_PREFIX "Error: "
203 #define WARNING_PREFIX "Warning: "
204 #define EXIT_PREFIX " An error spotted (non-EMBOSS): "
205 #define DIE_PREFIX "Died: "
206 #define CRASH_PREFIX_FORMAT "\n %s An error in %s at line %d:\n"
207 #define FULL_CRASH_PREFIX_FORMAT "\n %s Program cannot continue " \
208 "(%s, in file %s, at line %d):\n"
209 #define SYSERR_FORMAT "Something wrong with a system call (%d - %s)"
210 #define SYSERR_OK "Successful system call (%d - %s)"
211
212 /******************************************************************************
213 ** ajMessCrash now reports the file/line no. where ajMessCrash was issued
214 ** as an aid to debugging. We do this using a static structure which holds
215 ** the information and a macro version of ajMessCrash (see regular.h), the
216 ** structure elements are retrieved using access functions.
217 ******************************************************************************/
218
219
220
221
222 /* @datastatic MessPErrorInfo *************************************************
223 **
224 ** Message error information
225 **
226 ** @alias MessSErrorInfo
227 ** @alias MessOErrorInfo
228 **
229 ** @attr progname [char*] Name of executable reporting error
230 ** @attr filename [char*] Filename where error was reported
231 ** @attr line_num [ajint] line number of file where error was reported.
232 ** @attr Padding [char[4]] Padding to alignment boundary
233 ** @@
234 ******************************************************************************/
235
236 typedef struct MessSErrorInfo
237 {
238 char* progname;
239 char* filename;
240 ajint line_num;
241 char Padding[4];
242 } MessOErrorInfo;
243
244 #define MessPErrorInfo MessOErrorInfo*
245
246 static MessOErrorInfo messageG = {NULL, NULL, 0, ""};
247
248 static ajint messGetErrorLine(void);
249 static char *messGetErrorFile(void);
250 static char *messGetErrorProgram(void);
251
252 /***************************************************************/
253 /********* call backs and functions to register them ***********/
254
255 static AjMessVoidRoutine beepRoutine = 0;
256 static AjMessOutRoutine outRoutine = 0;
257 static AjMessOutRoutine dumpRoutine = 0;
258 static AjMessOutRoutine errorRoutine = 0;
259 static AjMessOutRoutine exitRoutine = 0;
260 static AjMessOutRoutine crashRoutine = 0;
261 static AjMessOutRoutine warningRoutine = 0;
262
263
264
265
266 /* @func ajMessRegBeep ********************************************************
267 **
268 ** Sets a function to process beeps
269 **
270 ** @param [f] func [AjMessVoidRoutine] Function to be registered
271 ** @return [AjMessVoidRoutine] Previously defined function
272 **
273 ** @release 2.9.0
274 ** @@
275 ******************************************************************************/
276
ajMessRegBeep(AjMessVoidRoutine func)277 AjMessVoidRoutine ajMessRegBeep(AjMessVoidRoutine func)
278 {
279 AjMessVoidRoutine old;
280
281 old = beepRoutine;
282 beepRoutine = func;
283
284 return old;
285 }
286
287
288
289
290 /* @func ajMessRegOut *********************************************************
291 **
292 ** Sets a function to write messages
293 **
294 ** @param [f] func [AjMessOutRoutine] Function to be registered
295 ** @return [AjMessOutRoutine] Previously defined function
296 **
297 ** @release 2.9.0
298 ** @@
299 ******************************************************************************/
300
ajMessRegOut(AjMessOutRoutine func)301 AjMessOutRoutine ajMessRegOut(AjMessOutRoutine func)
302 {
303 AjMessOutRoutine old;
304
305 old = outRoutine;
306 outRoutine = func;
307
308 return old;
309 }
310
311
312
313
314 /* @func ajMessRegDump ********************************************************
315 **
316 ** Sets a function to dump data
317 **
318 ** @param [f] func [AjMessOutRoutine] Function to be registered
319 ** @return [AjMessOutRoutine] Previously defined function
320 **
321 ** @release 2.9.0
322 ** @@
323 ******************************************************************************/
324
ajMessRegDump(AjMessOutRoutine func)325 AjMessOutRoutine ajMessRegDump(AjMessOutRoutine func)
326 {
327 AjMessOutRoutine old;
328
329 old = dumpRoutine;
330 dumpRoutine = func;
331
332 return old;
333 }
334
335
336
337
338 /* @func ajMessRegErr *********************************************************
339 **
340 ** Sets a function to report errors
341 **
342 ** @param [f] func [AjMessOutRoutine] Function to be registered
343 ** @return [AjMessOutRoutine] Previously defined function
344 **
345 ** @release 2.9.0
346 ** @@
347 ******************************************************************************/
348
ajMessRegErr(AjMessOutRoutine func)349 AjMessOutRoutine ajMessRegErr(AjMessOutRoutine func)
350 {
351 AjMessOutRoutine old;
352
353 old = errorRoutine;
354 errorRoutine = func;
355
356 return old;
357 }
358
359
360
361
362 /* @func ajMessRegExit ********************************************************
363 **
364 ** Sets a function to exit
365 **
366 ** @param [f] func [AjMessOutRoutine] Function to be registered
367 ** @return [AjMessOutRoutine] Previously defined function
368 **
369 ** @release 2.9.0
370 ** @@
371 ******************************************************************************/
372
ajMessRegExit(AjMessOutRoutine func)373 AjMessOutRoutine ajMessRegExit(AjMessOutRoutine func)
374 {
375 AjMessOutRoutine old;
376
377 old = exitRoutine;
378 exitRoutine = func;
379
380 return old;
381 }
382
383
384
385
386 /* @func ajMessRegCrash *******************************************************
387 **
388 ** Sets a function to crash
389 **
390 ** @param [f] func [AjMessOutRoutine] Function to be registered
391 ** @return [AjMessOutRoutine] Previously defined function
392 **
393 ** @release 2.9.0
394 ** @@
395 ******************************************************************************/
396
ajMessRegCrash(AjMessOutRoutine func)397 AjMessOutRoutine ajMessRegCrash(AjMessOutRoutine func)
398 {
399 AjMessOutRoutine old;
400
401 old = crashRoutine;
402 crashRoutine = func;
403
404 return old;
405 }
406
407
408
409
410 /* @func ajMessRegWarn ********************************************************
411 **
412 ** Sets a function to print warnings
413 **
414 ** @param [f] func [AjMessOutRoutine] Function to be registered
415 ** @return [AjMessOutRoutine] Previously defined function
416 **
417 ** @release 2.9.0
418 ** @@
419 ******************************************************************************/
420
ajMessRegWarn(AjMessOutRoutine func)421 AjMessOutRoutine ajMessRegWarn(AjMessOutRoutine func)
422 {
423 AjMessOutRoutine old;
424
425 old = warningRoutine;
426 warningRoutine = func;
427
428 return old;
429 }
430
431
432
433
434 /* @func ajMessBeep ***********************************************************
435 **
436 ** Calls the defined beep function, if any. Otherwise prints ASCII 7 to
437 ** standard error.
438 **
439 ** @return [void]
440 **
441 ** @release 1.0.0
442 ** @@
443 ******************************************************************************/
444
ajMessBeep(void)445 void ajMessBeep(void)
446 {
447 if(beepRoutine)
448 (*beepRoutine)();
449 else
450 {
451 printf("%c",0x07);
452 fflush(stdout);
453 }
454
455 return;
456 }
457
458
459
460
461 /* @func ajUser ***************************************************************
462 **
463 ** Formats a message. Calls the defined output function (if any).
464 ** Otherwise prints the message to standard error with an extra newline.
465 **
466 ** @param [r] format [const char*] Format string
467 ** @param [v] [...] Variable length argument list
468 ** @return [void]
469 **
470 ** @release 2.9.0
471 ** @@
472 ******************************************************************************/
473
ajUser(const char * format,...)474 void ajUser(const char *format,...)
475 {
476 va_list args;
477 const char *mesg_buf;
478
479 AJAXFORMATSTRING(args, format, mesg_buf, NULL);
480
481 if(outRoutine)
482 (*outRoutine)(mesg_buf);
483 else
484 fprintf(stderr, "%s\n", mesg_buf);
485
486 ajDebug("ajUser: %s\n", mesg_buf);
487
488 return;
489 }
490
491
492
493
494 /* @func ajUserDumpC **********************************************************
495 **
496 ** Prints a string unchanged. Calls the defined output function (if any).
497 ** Otherwise prints the message to standard error with an extra newline.
498 **
499 ** @param [r] txt [const char*] String to print unchanged
500 ** @return [void]
501 **
502 ** @release 6.0.0
503 ** @@
504 ******************************************************************************/
505
ajUserDumpC(const char * txt)506 void ajUserDumpC(const char* txt)
507 {
508 if(outRoutine)
509 (*outRoutine)(txt);
510 else
511 fprintf(stderr, "%s\n", txt);
512
513 ajDebug("ajUserDumpC: %s\n", txt);
514
515 return;
516 }
517
518
519
520
521 /* @func ajUserDumpS **********************************************************
522 **
523 ** Prints a string unchanged. Calls the defined output function (if any).
524 ** Otherwise prints the message to standard error with an extra newline.
525 **
526 ** @param [r] str [const AjPStr] String to print unchanged
527 ** @return [void]
528 **
529 ** @release 6.0.0
530 ** @@
531 ******************************************************************************/
532
ajUserDumpS(const AjPStr str)533 void ajUserDumpS(const AjPStr str)
534 {
535 const char *mesg_buf = ajStrGetPtr(str);
536
537 if(outRoutine)
538 (*outRoutine)(mesg_buf);
539 else
540 fprintf(stderr, "%s\n", mesg_buf);
541
542 ajDebug("ajUserDumpS: %s\n", mesg_buf);
543
544 return;
545 }
546
547
548
549
550 /* @func ajMessOut ************************************************************
551 **
552 ** Formats a message. Calls the defined output function (if any).
553 ** Otherwise prints the message to standard error with no newline.
554 **
555 ** @param [r] format [const char*] Format string
556 ** @param [v] [...] Variable length argument list
557 ** @return [void]
558 **
559 ** @release 1.0.0
560 ** @@
561 ******************************************************************************/
562
ajMessOut(const char * format,...)563 void ajMessOut(const char *format,...)
564 {
565 va_list args;
566 char *mesg_buf;
567
568 AJAXFORMATSTRING(args, format, mesg_buf, NULL);
569
570 if(outRoutine)
571 (*outRoutine)(mesg_buf);
572 else
573 fprintf(stderr, "%s", mesg_buf);
574
575 ajDebug("ajMessOut: %s\n", mesg_buf);
576
577 return;
578 }
579
580
581
582
583 /* @func ajVUser **************************************************************
584 **
585 ** Formats a message. Calls the defined output function (if any).
586 ** Otherwise prints the message to standard error.
587 **
588 ** @param [r] format [const char*] Format string
589 ** @param [v] args [va_list] Variable length argument list
590 ** @return [void]
591 **
592 ** @release 2.9.0
593 ** @@
594 ******************************************************************************/
595
ajVUser(const char * format,va_list args)596 void ajVUser(const char *format, va_list args)
597 {
598 char *mesg_buf;
599
600 AJAXVFORMATSTRING(args, format, mesg_buf, NULL);
601
602 if(outRoutine)
603 (*outRoutine)(mesg_buf);
604 else
605 fprintf(stderr, "%s\n", mesg_buf);
606
607 ajDebug("ajVUser: %s\n", mesg_buf);
608
609 return;
610 }
611
612
613
614
615 /* @func ajMessDump ***********************************************************
616 **
617 ** Formats a message. Calls the dump function (if any).
618 ** Otherwise no further action.
619 **
620 ** @param [r] format [const char*] format string.
621 ** @param [v] [...] Variable length argument list.
622 ** @return [void]
623 **
624 ** @release 1.0.0
625 ** @@
626 ******************************************************************************/
627
ajMessDump(const char * format,...)628 void ajMessDump(const char *format,...)
629 {
630 static char dumpbuf[BUFSIZE]; /* BEWARE limited buffer size. */
631 char *mesg_buf;
632 va_list args;
633
634 mesg_buf = &dumpbuf[0];
635
636 AJAXFORMATSTRING(args, format, mesg_buf, NULL);
637
638 strcat(mesg_buf, "\n"); /* assume we are writing to a file */
639
640 if(dumpRoutine)
641 (*dumpRoutine)(mesg_buf);
642
643 return;
644 }
645
646
647
648
649 /* @funcstatic messDump *******************************************************
650 **
651 ** Calls the dump function (if any) to dump text followed by a newline.
652 **
653 ** @param [r] message [const char*] Message text
654 ** @return [void]
655 **
656 ** @release 1.0.0
657 ** @@
658 ******************************************************************************/
659
messDump(const char * message)660 static void messDump(const char *message)
661 {
662 if(dumpRoutine)
663 {
664 (*dumpRoutine)(message);
665 (*dumpRoutine)("\n");
666 }
667
668 return;
669 }
670
671
672
673
674 /* @func ajMessGetCountError **************************************************
675 **
676 ** Returns the number of times the error routines have been called.
677 **
678 ** @return [ajint] Error function call count.
679 **
680 ** @release 6.2.0
681 ** @@
682 ******************************************************************************/
683
ajMessGetCountError(void)684 ajint ajMessGetCountError(void)
685 {
686 return errorCount;
687 }
688
689
690
691
692 /* @func ajErr ****************************************************************
693 **
694 ** Formats an error message. Calls the error function (if any).
695 ** Otherwise prints the message to standard error with a trailing newline.
696 **
697 ** The error message count is incremented by 1 for each call.
698 **
699 ** @param [r] format [const char*] Format
700 ** @param [v] [...] Variable length argument list
701 ** @return [void]
702 **
703 ** @release 2.9.0
704 ** @@
705 ******************************************************************************/
706
ajErr(const char * format,...)707 void ajErr(const char *format, ...)
708 {
709 const char *prefix = ERROR_PREFIX;
710 const char *mesg_buf = NULL;
711 va_list args;
712
713 ++errorCount;
714
715 if(AjErrorLevel.error)
716 {
717 AJAXFORMATSTRING(args, format, mesg_buf, prefix);
718
719 messDump(mesg_buf);
720
721 if(errorRoutine)
722 (*errorRoutine)(mesg_buf);
723 else
724 fprintf(stderr, "%s\n", mesg_buf);
725
726 ajDebug("ajErr: %s\n", mesg_buf);
727
728 ajMessInvokeDebugger();
729 ajUtilCatch();
730 }
731
732 return;
733 }
734
735
736
737
738 /* @func ajVErr ***************************************************************
739 **
740 ** Formats an error message. Calls the error function (if any).
741 ** Otherwise prints the message to standard error with a trailing newline.
742 **
743 ** The error message count is incremented by 1 for each call.
744 **
745 ** @param [r] format [const char*] Format
746 ** @param [v] args [va_list] Variable length argument list
747 ** @return [void]
748 **
749 ** @release 2.9.0
750 ** @@
751 ******************************************************************************/
752
ajVErr(const char * format,va_list args)753 void ajVErr(const char *format, va_list args)
754 {
755 const char *prefix = ERROR_PREFIX;
756 const char *mesg_buf = NULL;
757
758 ++errorCount;
759
760 AJAXVFORMATSTRING(args, format, mesg_buf, prefix);
761
762 messDump(mesg_buf);
763
764 if(errorRoutine)
765 (*errorRoutine)(mesg_buf);
766 else
767 {
768 if(AjErrorLevel.error)
769 {
770 fprintf(stderr, "%s\n", mesg_buf);
771 ajDebug("ajVErr: %s\n", mesg_buf);
772 }
773 }
774 ajMessInvokeDebugger();
775
776 return;
777 }
778
779
780
781
782 /* @func ajDie ****************************************************************
783 **
784 ** Formats an error message. Calls the error function (if any).
785 ** Otherwise prints the message to standard error with a trailing newline.
786 ** Then kills the application.
787 **
788 ** The error message count is incremented by 1 for each call.
789 **
790 ** @param [r] format [const char*] Format
791 ** @param [v] [...] Variable length argument list
792 ** @return [void]
793 **
794 ** @release 2.9.0
795 ** @@
796 ******************************************************************************/
797
ajDie(const char * format,...)798 __noreturn void ajDie(const char *format, ...)
799 {
800 const char *prefix = DIE_PREFIX;
801 const char *mesg_buf = NULL;
802 va_list args;
803
804 ++errorCount;
805
806 if(AjErrorLevel.die)
807 {
808 AJAXFORMATSTRING(args, format, mesg_buf, prefix);
809
810 messDump(mesg_buf);
811
812 if(errorRoutine)
813 (*errorRoutine)(mesg_buf);
814 else
815 fprintf(stderr, "%s\n", mesg_buf);
816
817 ajDebug("ajDie: %s\n", mesg_buf);
818
819 ajMessInvokeDebugger();
820 }
821
822
823 exit(EXIT_FAILURE);
824 }
825
826
827
828
829 /* @func ajVDie ***************************************************************
830 **
831 ** Formats an error message. Calls the error function (if any).
832 ** Otherwise prints the message to standard error with a trailing newline.
833 ** Then kills the application.
834 **
835 ** The error message count is incremented by 1 for each call.
836 **
837 ** @param [r] format [const char*] Format
838 ** @param [v] args [va_list] Variable length argument list
839 ** @return [void]
840 **
841 ** @release 2.9.0
842 ** @@
843 ******************************************************************************/
844
ajVDie(const char * format,va_list args)845 void ajVDie(const char *format, va_list args)
846 {
847 const char *prefix = DIE_PREFIX;
848 const char *mesg_buf = NULL;
849
850 ++errorCount;
851
852 AJAXVFORMATSTRING(args, format, mesg_buf, prefix);
853
854 messDump(mesg_buf);
855
856 if(errorRoutine)
857 (*errorRoutine)(mesg_buf);
858 else
859 ajMessCrash(mesg_buf);
860
861 ajMessInvokeDebugger();
862
863 return;
864 }
865
866
867
868
869 /* @func ajWarn ***************************************************************
870 **
871 ** Formats a warning message. Calls the warning function (if any).
872 ** Otherwise prints the message to standard error with a trailing newline.
873 **
874 ** @param [r] format [const char*] Format
875 ** @param [v] [...] Variable length argument list
876 ** @return [void]
877 **
878 ** @release 2.9.0
879 ** @@
880 ******************************************************************************/
881
ajWarn(const char * format,...)882 void ajWarn(const char *format, ...)
883 {
884 const char *prefix = WARNING_PREFIX;
885 const char *mesg_buf = NULL;
886 va_list args;
887
888 if(AjErrorLevel.warning)
889 {
890 AJAXFORMATSTRING(args, format, mesg_buf, prefix);
891
892 messDump(mesg_buf);
893
894 if(warningRoutine)
895 (*warningRoutine)(mesg_buf);
896 else
897 fprintf(stderr, "%s\n", mesg_buf);
898
899 ajDebug("ajWarn: %s\n", mesg_buf);
900
901 ajMessInvokeDebugger();
902 ajUtilCatch();
903 }
904
905 return;
906 }
907
908
909
910
911 /* @func ajVWarn **************************************************************
912 **
913 ** Formats a warning message. Calls the warning function (if any).
914 ** Otherwise prints the message to standard error with a trailing newline.
915 **
916 ** @param [r] format [const char*] Format
917 ** @param [v] args [va_list] Variable length argument list
918 ** @return [void]
919 **
920 ** @release 2.9.0
921 ** @@
922 ******************************************************************************/
923
ajVWarn(const char * format,va_list args)924 void ajVWarn(const char *format, va_list args)
925 {
926 const char *prefix = WARNING_PREFIX;
927 const char *mesg_buf = NULL;
928
929 AJAXVFORMATSTRING(args, format, mesg_buf, prefix);
930
931 messDump(mesg_buf);
932
933 if(warningRoutine)
934 (*warningRoutine)(mesg_buf);
935 else
936 fprintf(stderr, "%s\n", mesg_buf);
937
938 ajDebug("ajVWarn: %s\n", mesg_buf);
939
940 ajMessInvokeDebugger();
941
942 return;
943 }
944
945
946
947
948 /* @func ajMessExitmsg ********************************************************
949 **
950 ** Formats an exit message and calls the exit function (if any).
951 ** Otherwise prints the message to standard error with a trailing newline
952 ** and exist with code EXIT_FAILURE.
953 **
954 ** Use this function for errors that while being unrecoverable are not a
955 ** problem with the AJAX code.
956 **
957 ** Note that there errors are logged but that this routine will exit without
958 ** any chance to interrupt it (see the crash routine in ajMessCrashFL), this
959 ** could be changed to allow the application to register an exit handler.
960 **
961 ** @param [r] format [const char*] Format
962 ** @param [v] [...] Variable length argument list
963 ** @return [void]
964 **
965 ** @release 2.7.0
966 ** @@
967 ******************************************************************************/
968
ajMessExitmsg(const char * format,...)969 __noreturn void ajMessExitmsg(const char *format, ...)
970 {
971 const char *prefix = EXIT_PREFIX;
972 const char *mesg_buf = NULL;
973 va_list args;
974
975 AJAXFORMATSTRING(args, format, mesg_buf, prefix);
976
977 messDump(mesg_buf);
978
979 if(exitRoutine)
980 (*exitRoutine)(mesg_buf);
981 else
982 fprintf(stderr, "%s\n", mesg_buf);
983
984 ajDebug("ajMessExitmsg: %s\n", mesg_buf);
985
986 exit(EXIT_FAILURE);
987 }
988
989
990
991
992 /* @func ajMessCrashFL ********************************************************
993 **
994 ** This is the routine called by the ajFatal macro and others.
995 **
996 ** This routine may encounter errors itself, in which case it will attempt
997 ** to call itself to report the error. To avoid infinite recursion we limit
998 ** this to just one reporting of an internal error and then we abort.
999 **
1000 ** @param [r] format [const char*] Format
1001 ** @param [v] [...] Variable length argument list
1002 ** @return [void]
1003 **
1004 ** @release 1.0.0
1005 ** @@
1006 ******************************************************************************/
1007
ajMessCrashFL(const char * format,...)1008 __noreturn void ajMessCrashFL(const char *format, ...)
1009 {
1010 enum {MAXERRORS = 1};
1011 static ajint internalErrors = 0;
1012 static char prefix[1024];
1013 ajint rc;
1014 const char *mesg_buf = NULL;
1015 va_list args;
1016
1017
1018 if(internalErrors > MAXERRORS)
1019 abort();
1020 else
1021 internalErrors++;
1022
1023 /* Construct the message prefix, adding the program name if possible. */
1024
1025 if(messGetErrorProgram() == NULL)
1026 rc = sprintf(prefix, CRASH_PREFIX_FORMAT, MESG_TITLE,
1027 messGetErrorFile(), messGetErrorLine());
1028 else
1029 rc = sprintf(prefix, FULL_CRASH_PREFIX_FORMAT, MESG_TITLE,
1030 messGetErrorProgram(), messGetErrorFile(),
1031 messGetErrorLine());
1032 if(rc < 0)
1033 ajMessCrash("sprintf failed");
1034
1035 if(AjErrorLevel.fatal)
1036 {
1037 AJAXFORMATSTRING(args, format, mesg_buf, prefix);
1038
1039 messDump(mesg_buf);
1040
1041 if(crashRoutine)
1042 (*crashRoutine)(mesg_buf);
1043 else
1044 fprintf(stderr, "%s\n", mesg_buf);
1045
1046 ajDebug("ajMessCrashFL: %s\n", mesg_buf);
1047
1048 ajMessInvokeDebugger();
1049 }
1050
1051
1052 exit(EXIT_FAILURE);
1053 }
1054
1055
1056
1057
1058 /* @func ajMessVCrashFL *******************************************************
1059 **
1060 ** This is the routine called by the ajVFatal macro and others.
1061 **
1062 ** This routine may encounter errors itself, in which case it will attempt
1063 ** to call itself to report the error. To avoid infinite recursion we limit
1064 ** this to just one reporting of an internal error and then we abort.
1065 **
1066 ** @param [r] format [const char*] Format
1067 ** @param [v] args [va_list] Variable length argument list
1068 ** @return [void]
1069 **
1070 ** @release 1.0.0
1071 ** @@
1072 ******************************************************************************/
1073
ajMessVCrashFL(const char * format,va_list args)1074 __noreturn void ajMessVCrashFL(const char *format, va_list args)
1075 {
1076 enum {MAXERRORS = 1};
1077 static ajint internalErrors = 0;
1078 static char prefix[1024];
1079 ajint rc;
1080 char *mesg_buf = NULL;
1081
1082 if(internalErrors > MAXERRORS)
1083 abort();
1084 else
1085 internalErrors++;
1086
1087 /* Construct the message prefix, adding the program name if possible. */
1088
1089 if(messGetErrorProgram() == NULL)
1090 rc = sprintf(prefix, CRASH_PREFIX_FORMAT, MESG_TITLE,
1091 messGetErrorFile(), messGetErrorLine());
1092 else
1093 rc = sprintf(prefix, FULL_CRASH_PREFIX_FORMAT, MESG_TITLE,
1094 messGetErrorProgram(), messGetErrorFile(),
1095 messGetErrorLine());
1096 if(rc < 0)
1097 ajMessCrash("sprintf failed");
1098
1099
1100 AJAXVFORMATSTRING(args, format, mesg_buf, prefix);
1101
1102 messDump(mesg_buf);
1103
1104 if(crashRoutine)
1105 (*crashRoutine)(mesg_buf);
1106 else
1107 fprintf(stderr, "%s\n", mesg_buf);
1108
1109 ajDebug("ajMessVCrashFL: %s\n", mesg_buf);
1110
1111 ajMessInvokeDebugger();
1112
1113 exit(EXIT_FAILURE);
1114 }
1115
1116
1117
1118
1119 /* @func ajMessGetMessageC ****************************************************
1120 **
1121 ** Returns the current message text.
1122 **
1123 ** @return [const char*] Message text
1124 **
1125 ** @release 6.2.0
1126 ** @@
1127 ******************************************************************************/
1128
ajMessGetMessageC(void)1129 const char* ajMessGetMessageC(void)
1130 {
1131 return messbuf;
1132 }
1133
1134
1135
1136
1137 /* @func ajMessGetSysmessageC *************************************************
1138 **
1139 ** Returns the system message text from 'strerror' from the standard C
1140 ** library.
1141 **
1142 ** @return [const char*] System error message.
1143 **
1144 ** @release 6.2.0
1145 ** @@
1146 ******************************************************************************/
1147
ajMessGetSysmessageC(void)1148 const char* ajMessGetSysmessageC(void)
1149 {
1150 char *mess;
1151
1152 if(errno)
1153 mess = ajFmtString(SYSERR_FORMAT, errno, strerror(errno));
1154 else
1155 mess = ajFmtString(SYSERR_OK, errno, strerror(errno));
1156
1157 /* must make copy - will be used when mess* calls itself */
1158 AJFREE(messErrMess);
1159 messErrMess = ajSysFuncStrdup(mess);
1160
1161 AJFREE(mess);
1162
1163 return messErrMess;
1164 }
1165
1166
1167
1168
1169 /************************* message formatting ********************************/
1170 /* This routine does the formatting of the message string using vsprintf, */
1171 /* it copes with the format string accidentally being our internal buffer. */
1172 /* */
1173 /* This routine does its best to check that the vsprintf is successful, if */
1174 /* not the routine bombs out with an error message. Note that num_bytes is */
1175 /* the return value from vsprintf. */
1176 /* Failures trapped: */
1177 /* num_bytes less than 0 = vsprintf failed, reason is reported. */
1178 /* num_bytes + 1 more than BUFSIZE = our internal buffer size was */
1179 /* exceeded. */
1180 /* (vsprintf returns number of bytes written */
1181 /* _minus_ terminating NULL) */
1182 /* */
1183
1184
1185
1186
1187 /* @funcstatic messFormat *****************************************************
1188 **
1189 ** Used by the AJAXFORMAT macros to format messages.
1190 **
1191 ** This routine does the formatting of the message string using vsprintf,
1192 ** it copes with the format string accidentally being our internal buffer.
1193 **
1194 ** This routine does its best to check that the vsprintf is successful, if
1195 ** not the routine bombs out with an error message. Note that num_bytes is
1196 ** the return value from vsprintf.
1197 **
1198 ** Failures trapped:
1199 ** num_bytes less than 0 = vsprintf failed, reason is reported.
1200 ** num_bytes + 1 more than BUFSIZE = our internal buffer size was exceeded.
1201 ** (vsprintf returns number of bytes written
1202 ** _minus_ terminating NULL)
1203 **
1204 ** @param [v] args [va_list] Variable length argument list
1205 ** @param [r] format [const char*] Format string
1206 ** @param [r] prefix [const char*] Message prefix
1207 ** @return [char*] Formatted message text
1208 **
1209 ** @release 1.0.0
1210 ** @@
1211 ******************************************************************************/
1212
messFormat(va_list args,const char * format,const char * prefix)1213 static char* messFormat(va_list args, const char *format, const char *prefix)
1214 {
1215 static char *new_buf = NULL;
1216 char *buf_ptr;
1217 ajint num_bytes;
1218 ajint prefix_len;
1219
1220
1221 if(format == NULL)
1222 ajMessCrash("invalid call, no format string.");
1223
1224 if(prefix == NULL)
1225 prefix_len = 0;
1226 else
1227 {
1228 prefix_len = strlen(prefix);
1229 if((prefix_len + 1) > PREFIXSIZE)
1230 ajMessCrash("prefix string is too long.");
1231 }
1232
1233
1234 /* If they supply the internal buffer as an argument, e.g. because they */
1235 /* used ajFmtString as an arg, then make a copy, otherwise use internal */
1236 /* buffer. */
1237
1238 if(format == messbuf)
1239 {
1240 if(new_buf != NULL)
1241 AJFREE(new_buf);
1242 buf_ptr = new_buf = ajSysFuncStrdup(format);
1243 }
1244 else
1245 buf_ptr = messbuf;
1246
1247 /* Add the prefix if there is one. */
1248 if(prefix != NULL)
1249 {
1250 if(!strcpy(buf_ptr, prefix))
1251 ajMessCrash("strcpy failed");
1252 }
1253
1254
1255 num_bytes = prefix_len + 1;
1256 num_bytes += ajFmtVPrintCL((buf_ptr + prefix_len),BUFSIZE, format, args);
1257
1258 /*
1259 ** Check the result. This should never happen using the
1260 ** ajFmtVPrintCL routine instead of the vsprintf routine
1261 */
1262
1263 if(num_bytes < 0)
1264 ajMessCrash("vsprintf failed: %s", ajMessGetSysmessageC());
1265 else if(num_bytes > BUFSIZE)
1266 ajMessCrash("messubs internal buffer size (%d) exceeded, "
1267 "a total of %d bytes were written",
1268 BUFSIZE, num_bytes);
1269
1270 return(buf_ptr);
1271 }
1272
1273
1274
1275
1276 /* @funcstatic messGetFilename ************************************************
1277 **
1278 ** Converts a filename into a base file name. Used for filenames passed
1279 ** by macros from __FILE__ which could include part or all of the path
1280 ** depending on how the source code was compiled.
1281 **
1282 ** @param [r] path [const char*] File name, possibly with full path.
1283 ** @return [char*] Base file name
1284 **
1285 ** @release 1.0.0
1286 ** @@
1287 ******************************************************************************/
1288
messGetFilename(const char * path)1289 static char* messGetFilename(const char *path)
1290 {
1291 static char *path_copy = NULL;
1292 const char *path_delim = SUBDIR_DELIMITER_STR;
1293 char *result = NULL;
1294 char *tmp;
1295
1296 if(path != NULL)
1297 {
1298 if(strcmp((path + strlen(path) - 1), path_delim) != 0)
1299 { /* Last char = "/" ?? */
1300 if(path_copy != NULL)
1301 AJFREE(path_copy);
1302
1303 path_copy = ajSysFuncStrdup(path);
1304
1305 tmp = ajSysFuncStrtok(path_copy, path_delim);
1306
1307 while(tmp != NULL)
1308 {
1309 result = tmp; /* Keep results of previous strtok */
1310
1311 tmp = ajSysFuncStrtok(NULL, path_delim);
1312 }
1313 }
1314 }
1315
1316 return(result);
1317 }
1318
1319
1320
1321
1322 /*
1323 ** When AJAX needs to crash because there has been an unrecoverable
1324 ** error the file and line number of the code that detected the error
1325 ** need to be output. Here are the functions to do it.
1326 **
1327 ** Applications can optionally initialise the error handling section of the
1328 ** message package, currently the program name can be set (argv[0] in the
1329 ** main routine) as there is no easy way to get at this at run time except
1330 ** from the main.
1331 ** */
1332
1333
1334
1335
1336 /* @func ajMessErrorInit ******************************************************
1337 **
1338 ** Initialises the stored program name.
1339 **
1340 ** @param [r] progname [const char*] Program name.
1341 ** @return [void]
1342 **
1343 ** @release 1.0.0
1344 ** @@
1345 ******************************************************************************/
1346
ajMessErrorInit(const char * progname)1347 void ajMessErrorInit(const char *progname)
1348 {
1349 if(progname != NULL)
1350 messageG.progname = ajSysFuncStrdup(messGetFilename(progname));
1351
1352 return;
1353 }
1354
1355
1356
1357
1358 /* @func ajMessSetErr *********************************************************
1359 **
1360 ** Stores the source file name (converted to a base name)
1361 ** and the source line number to be
1362 ** reported by the crash routines.
1363 **
1364 ** Invoked automatically by a macro (e.g. ajFatal) where needed.
1365 **
1366 ** @param [r] filename [const char*] source filename, __FILE__
1367 ** @param [r] line_num [ajint] source line number, __LINE__
1368 ** @return [void]
1369 **
1370 ** @release 1.0.0
1371 ** @@
1372 ******************************************************************************/
1373
ajMessSetErr(const char * filename,ajint line_num)1374 void ajMessSetErr(const char *filename, ajint line_num)
1375 {
1376 assert(filename != NULL && line_num != 0);
1377
1378 /*
1379 ** We take the basename here because __FILE__ can be a path rather
1380 ** than just a filename, depending on how a module was compiled.
1381 */
1382
1383 messageG.filename = ajSysFuncStrdup(messGetFilename(filename));
1384
1385 messageG.line_num = line_num;
1386
1387 ajUtilCatch();
1388
1389 return;
1390 }
1391
1392
1393
1394
1395 /* Access functions for message error data. */
1396
1397
1398
1399
1400 /* @funcstatic messGetErrorProgram ********************************************
1401 **
1402 ** Returns the stored program name.
1403 **
1404 ** @return [char*] Program name
1405 **
1406 ** @release 1.0.0
1407 ** @@
1408 ******************************************************************************/
1409
messGetErrorProgram(void)1410 static char* messGetErrorProgram(void)
1411 {
1412 return(messageG.progname);
1413 }
1414
1415
1416
1417
1418 /* @funcstatic messGetErrorFile ***********************************************
1419 **
1420 ** Returns the stored error file name.
1421 **
1422 ** @return [char*] Error file name
1423 **
1424 ** @release 1.0.0
1425 ** @@
1426 ******************************************************************************/
1427
messGetErrorFile(void)1428 static char* messGetErrorFile(void)
1429 {
1430 return(messageG.filename);
1431 }
1432
1433
1434
1435
1436 /* @funcstatic messGetErrorLine ***********************************************
1437 **
1438 ** Returns the stored error source line number.
1439 **
1440 ** @return [ajint] Original source code line number
1441 **
1442 ** @release 1.0.0
1443 ** @@
1444 ******************************************************************************/
1445
messGetErrorLine(void)1446 static ajint messGetErrorLine(void)
1447 {
1448 return(messageG.line_num);
1449 }
1450
1451
1452
1453
1454 /* set a file to read for all the messages. NB if this is not set
1455 Then a default one will be read */
1456
1457
1458
1459
1460 /* @func ajMessErrorSetFile ***************************************************
1461 **
1462 ** Opens a file and sets this to be the error file.
1463 **
1464 ** @param [r] errfile [const char*] Error file name
1465 ** @return [AjBool] ajTrue on success
1466 **
1467 ** @release 1.0.0
1468 ** @@
1469 ******************************************************************************/
1470
ajMessErrorSetFile(const char * errfile)1471 AjBool ajMessErrorSetFile(const char *errfile)
1472 {
1473 FILE *fp = 0;
1474
1475 if(errfile)
1476 if((fp = fopen(errfile,"r")))
1477 {
1478 messErrorFile = ajSysFuncStrdup(errfile);
1479 fclose(fp);
1480
1481 return ajTrue;
1482 }
1483
1484 return ajFalse;
1485 }
1486
1487
1488
1489
1490 /* @funcstatic ajMessReadErrorFile ********************************************
1491 **
1492 ** Reads the error message file (with a default of
1493 ** $EMBOSS_ROOT/messages/messages.english)
1494 ** and loads the results into an internal table.
1495 **
1496 ** @return [AjBool] ajTrue on success
1497 **
1498 ** @release 1.0.0
1499 ** @@
1500 ******************************************************************************/
1501
ajMessReadErrorFile(void)1502 static AjBool ajMessReadErrorFile(void)
1503 {
1504 char line[512];
1505 char name[12];
1506 char message[200];
1507 FILE *fp=0;
1508 char *mess;
1509 char *cp;
1510 char *namestore;
1511 char *messstore;
1512
1513 if(messErrorFile)
1514 fp = fopen(messErrorFile,"r");
1515
1516 if(!fp)
1517 {
1518 messErrorFile = ajFmtString("%s/messages/messages.english",
1519 getenv("EMBOSS_ROOT"));
1520 fp = fopen(messErrorFile,"r");
1521 }
1522
1523
1524 if(!fp)
1525 return ajFalse;
1526
1527 messErrorTable = ajTablecharNew(100);
1528
1529 while(fgets(line, 512, fp))
1530 {
1531 if(sscanf(line,"%s %s",name,message)!=2)
1532 ajFatal("Library sscanf1");
1533
1534 cp = strchr(line,'"');
1535 cp++;
1536 mess = &message[0];
1537
1538 while(*cp != '"')
1539 {
1540 *mess = *cp;
1541 cp++;
1542 mess++;
1543 }
1544
1545 *mess = '\0';
1546 namestore = ajCharNewC(name);
1547 messstore = ajCharNewC(message);
1548
1549 if(ajTablePut(messErrorTable, namestore, messstore))
1550 ajErr("%s is listed more than once in file %s",
1551 name,messErrorFile);
1552 }
1553
1554 return ajTrue;
1555 }
1556
1557
1558
1559
1560 /* @func ajMessOutCode ********************************************************
1561 **
1562 ** Writes an output message for a given message code.
1563 **
1564 ** @param [r] code [const char*] Message code
1565 ** @return [void]
1566 **
1567 ** @release 1.0.0
1568 ** @@
1569 ******************************************************************************/
1570
ajMessOutCode(const char * code)1571 void ajMessOutCode(const char *code)
1572 {
1573 const char *mess=0;
1574
1575 if(messErrorTable)
1576 {
1577 mess = ajTableFetchC(messErrorTable, code);
1578
1579 if(mess)
1580 ajMessOut(mess);
1581 else
1582 ajMessOut("could not find error code %s",code);
1583 }
1584 else
1585 {
1586 if(ajMessReadErrorFile())
1587 {
1588 mess = ajTableFetchC(messErrorTable, code);
1589
1590 if(mess)
1591 ajMessOut(mess);
1592 else
1593 ajMessOut("could not find error code %s",code);
1594 }
1595 else
1596 ajMessOut("Could not read the error file hence no reference to %s",
1597 code);
1598 }
1599
1600 return;
1601 }
1602
1603
1604
1605
1606 /* @func ajMessErrorCode ******************************************************
1607 **
1608 ** Writes an error message for a given message code.
1609 **
1610 ** @param [r] code [const char*] Error code
1611 ** @return [void]
1612 **
1613 ** @release 1.0.0
1614 ** @@
1615 ******************************************************************************/
1616
ajMessErrorCode(const char * code)1617 void ajMessErrorCode(const char *code)
1618 {
1619 const char *mess = 0;
1620
1621 if(messErrorTable)
1622 {
1623 mess = ajTableFetchC(messErrorTable, code);
1624
1625 if(mess)
1626 ajErr(mess);
1627 else
1628 ajErr("could not find error code %s",code);
1629 }
1630 else
1631 {
1632 if(ajMessReadErrorFile())
1633 {
1634 mess = ajTableFetchC(messErrorTable, code);
1635
1636 if(mess)
1637 ajErr(mess);
1638 else
1639 ajErr("could not find error code %s",code);
1640 }
1641 else
1642 ajErr("Could not read the error file, "
1643 "hence no reference to %s",
1644 code);
1645 }
1646
1647 return;
1648 }
1649
1650
1651
1652
1653 /* @func ajMessCrashCodeFL ****************************************************
1654 **
1655 ** Writes an error message for a given message code and crashes.
1656 **
1657 ** @param [r] code [const char*] Error code
1658 ** @return [void]
1659 **
1660 ** @release 1.0.0
1661 ** @@
1662 ******************************************************************************/
1663
ajMessCrashCodeFL(const char * code)1664 __noreturn void ajMessCrashCodeFL(const char *code)
1665 {
1666 const char *mess = 0;
1667
1668 if(messErrorTable)
1669 {
1670 mess = ajTableFetchC(messErrorTable, code);
1671
1672 if(mess)
1673 ajMessCrashFL(mess);
1674 else
1675 ajMessCrashFL("could not find error code %s",code);
1676 }
1677 else
1678 {
1679 if(ajMessReadErrorFile())
1680 {
1681 mess = ajTableFetchC(messErrorTable, code);
1682
1683 if(mess)
1684 ajMessCrashFL(mess);
1685 else
1686 ajMessCrashFL("could not find error code %s",code);
1687 }
1688 else
1689 ajMessCrashFL("Could not read the error file "
1690 "hence no reference to %s",
1691 code);
1692 }
1693 }
1694
1695
1696
1697
1698 /* @func ajMessCodesDelete ****************************************************
1699 **
1700 ** Deletes the message codes table.
1701 **
1702 ** @return [void]
1703 **
1704 ** @release 1.0.0
1705 ** @@
1706 ******************************************************************************/
1707
ajMessCodesDelete(void)1708 void ajMessCodesDelete(void)
1709 {
1710 messTableDelete(&messErrorTable);
1711 }
1712
1713
1714
1715
1716 /* @funcstatic messTableDelete ************************************************
1717 **
1718 ** Delete a table, simply freeing the key and value
1719 **
1720 ** @param [d] table [AjPTable*] Table
1721 ** @return [void]
1722 **
1723 ** @release 6.2.0
1724 ******************************************************************************/
1725
messTableDelete(AjPTable * table)1726 static void messTableDelete(AjPTable* table)
1727 {
1728 void **keyarray = NULL;
1729 void **valarray = NULL;
1730 ajint i;
1731
1732 if(!table)
1733 return;
1734 if(!*table)
1735 return;
1736
1737 ajTableToarrayKeysValues(*table, &keyarray, &valarray);
1738
1739 for(i = 0; keyarray[i]; i++)
1740 {
1741 AJFREE(keyarray[i]);
1742 AJFREE(valarray[i]);
1743 }
1744
1745 AJFREE(keyarray);
1746 AJFREE(valarray);
1747
1748 ajTableFree(table);
1749 *table = NULL;
1750
1751 return;
1752 }
1753
1754
1755
1756
1757 /* @func ajDebug **************************************************************
1758 **
1759 ** Writes a debug message to the debug file if debugging is on.
1760 ** Typically, debugging is turned on by adding '-debug' to the command line
1761 ** or by defining a variable prefix_DEBUG
1762 **
1763 ** Avoid using this call in any code which can be invoked before the command
1764 ** line processing is complete as it can be a problem to find a reasonable
1765 ** file name for debug output under these circumstances.
1766 **
1767 ** @param [r] fmt [const char*] Format.
1768 ** @param [v] [...] Variable argument list.
1769 ** @return [void]
1770 **
1771 ** @release 1.0.0
1772 ** @@
1773 ******************************************************************************/
1774
ajDebug(const char * fmt,...)1775 void ajDebug(const char* fmt, ...)
1776 {
1777 va_list args;
1778 static ajint debugset = 0;
1779 static ajint depth = 0;
1780 AjPStr bufstr = NULL;
1781
1782 if(depth)
1783 { /* recursive call, get out quick */
1784 if(messDebugFile)
1785 {
1786 va_start(args, fmt);
1787 ajFmtVPrintF(messDebugFile, fmt, args);
1788 va_end(args);
1789 }
1790
1791 return;
1792 }
1793
1794 depth++;
1795
1796 if(!debugset && acdDebugSet)
1797 {
1798 if(acdDebug)
1799 {
1800 ajFmtPrintS(&messDebugName, "%s.dbg", ajStrGetPtr(acdProgram));
1801 messDebugFile = ajFileNewOutNameS(messDebugName);
1802
1803 if(!messDebugFile)
1804 ajFatal("Cannot open debug file %S",messDebugName);
1805
1806 if(ajNamGetValueC("debugbuffer", &bufstr))
1807 {
1808 ajStrToBool(bufstr, &acdDebugBuffer);
1809 }
1810
1811 if(!acdDebugBuffer)
1812 ajFileSetUnbuffer(messDebugFile);
1813
1814 ajFmtPrintF(messDebugFile, "Debug file %F buffered:%B\n",
1815 messDebugFile, acdDebugBuffer);
1816 ajStrDel(&bufstr);
1817 }
1818
1819 messDebug = acdDebug;
1820
1821 debugset = 1;
1822 }
1823
1824 if(messDebug)
1825 {
1826
1827 va_start(args, fmt);
1828 ajFmtVPrintF(messDebugFile, fmt, args);
1829 va_end(args);
1830
1831 }
1832
1833 depth--;
1834
1835 return;
1836 }
1837
1838
1839
1840
1841 /* @func ajDebugOn ************************************************************
1842 **
1843 ** Test whether debugging is on.
1844 **
1845 ** @return [AjBool] True if user has enabled debugging
1846 **
1847 ** @release 6.4.0
1848 ** @@
1849 ******************************************************************************/
1850
ajDebugOn(void)1851 AjBool ajDebugOn(void)
1852 {
1853 return acdDebug;
1854 }
1855
1856
1857
1858
1859 /* @func ajDebugTest **********************************************************
1860 **
1861 ** Tests a token string and returns true if the user has requested debug output
1862 **
1863 ** @param [r] token [const char*] Token name
1864 ** @return [AjBool] True if token has debugging requested
1865 **
1866 ** @release 6.2.0
1867 ** @@
1868 ******************************************************************************/
1869
ajDebugTest(const char * token)1870 AjBool ajDebugTest(const char* token)
1871 {
1872 AjPStr filename = NULL;
1873 const char* debugtestname = ".debugtest";
1874 char* ctoken = NULL;
1875 AjPStr line = NULL;
1876 AjPStr strtoken = NULL;
1877 AjPStr rest = NULL;
1878 static ajint depth = 0;
1879
1880 struct
1881 {
1882 ajuint count;
1883 ajuint max;
1884 } *stats;
1885
1886 if(depth)
1887 return ajFalse;
1888
1889 depth++;
1890
1891 if(!messDebugTestInit)
1892 {
1893 filename = ajStrNewC(debugtestname);
1894
1895 if(ajFilenameExists(filename))
1896 {
1897 messDebugTestFile = ajFileNewInNameS(filename);
1898 }
1899 else
1900 {
1901 ajFmtPrintS(&filename, "%s%s%s",
1902 getenv("HOME"), SLASH_STRING, debugtestname);
1903 if(ajFilenameExists(filename))
1904 messDebugTestFile = ajFileNewInNameS(filename);
1905 }
1906 ajStrDel(&filename);
1907
1908 if(messDebugTestFile)
1909 {
1910 messDebugTestTable = ajTablecharNew(256);
1911
1912 while(ajReadlineTrim(messDebugTestFile, &line))
1913 {
1914 if(!ajStrCutComments(&line))
1915 continue;
1916 if(ajStrExtractFirst(line, &rest, &strtoken))
1917 {
1918 AJNEW0(stats);
1919 ctoken = ajCharNewS(strtoken);
1920 if(ajStrIsInt(rest))
1921 ajStrToUint(rest, &stats->max);
1922 else
1923 stats->max = UINT_MAX;
1924
1925 ajTablePut(messDebugTestTable, ctoken, stats);
1926 ctoken = NULL;
1927 stats = NULL;
1928 }
1929 }
1930
1931 ajStrDel(&line);
1932 ajStrDel(&strtoken);
1933 ajStrDel(&rest);
1934 ajFileClose(&messDebugTestFile);
1935 }
1936 messDebugTestInit = ajTrue;
1937 }
1938
1939 depth--;
1940
1941 if(!messDebugTestTable)
1942 return ajFalse;
1943
1944 depth++;
1945 stats = ajTableFetchmodC(messDebugTestTable, token);
1946 depth--;
1947
1948
1949 if(!stats)
1950 return ajFalse;
1951
1952 if(!stats->max)
1953 return ajTrue;
1954
1955 if(stats->count++ >= stats->max)
1956 return ajFalse;
1957
1958 return ajTrue;
1959 }
1960
1961
1962
1963
1964 /* @func ajMessGetDebugfile ***************************************************
1965 **
1966 ** Returns the file used for debug output, or NULL if no debug file is open.
1967 **
1968 ** @return [FILE*] C runtime library file handle for debug output.
1969 **
1970 ** @release 6.2.0
1971 ** @@
1972 ******************************************************************************/
1973
ajMessGetDebugfile(void)1974 FILE* ajMessGetDebugfile(void)
1975 {
1976 if(!messDebugFile)
1977 return NULL;
1978
1979 return ajFileGetFileptr(messDebugFile);
1980 }
1981
1982
1983
1984
1985 /* @func ajUserGet ************************************************************
1986 **
1987 ** Writes a prompt to the terminal and reads one line from the user.
1988 **
1989 ** @param [w] pthis [AjPStr*] Buffer for the user response.
1990 ** @param [r] fmt [const char*] Format string
1991 ** @param [v] [...] Variable argument list.
1992 ** @return [ajint] Length of response string.
1993 **
1994 ** @release 1.0.0
1995 ** @@
1996 ******************************************************************************/
1997
ajUserGet(AjPStr * pthis,const char * fmt,...)1998 ajint ajUserGet(AjPStr* pthis, const char* fmt, ...)
1999 {
2000 AjPStr thys;
2001 const char *cp;
2002 char *buff;
2003 va_list args;
2004 ajint ipos;
2005 ajint isize;
2006 ajint ilen;
2007 ajint jlen;
2008 ajint fileBuffSize = ajFileValueBuffsize();
2009
2010 va_start(args, fmt);
2011 ajFmtVError(fmt, args);
2012 va_end(args);
2013
2014 if(ajFileValueRedirectStdin())
2015 {
2016 ajUser("(Standard input in use: using default)");
2017 ajStrAssignC(pthis, "");
2018
2019 return ajStrGetLen(*pthis);
2020 }
2021
2022 ajStrSetRes(pthis, fileBuffSize);
2023 buff = ajStrGetuniquePtr(pthis);
2024 thys = *pthis;
2025 isize = ajStrGetRes(thys);
2026 ilen = 0;
2027 ipos = 0;
2028
2029
2030 /*ajDebug("ajUserGet buffer len: %d res: %d ptr: %x\n",
2031 ajStrGetLen(thys), ajStrGetRes(thys), thys->Ptr);*/
2032
2033 while(buff)
2034 {
2035
2036 #ifndef __ppc__
2037 cp = fgets(&buff[ipos], isize, stdin);
2038 #else
2039 cp = ajSysFuncFgets(&buff[ipos], isize, stdin);
2040 #endif
2041
2042 if(!cp && !ipos)
2043 {
2044 if(feof(stdin))
2045 {
2046 ajErr("Unable to get reply from user - end of standard input");
2047 ajExitBad();
2048 }
2049 else
2050 ajFatal("Error reading from user: '%s'\n",
2051 strerror(errno));
2052 }
2053
2054 jlen = strlen(&buff[ipos]);
2055 ilen += jlen;
2056
2057 /*
2058 ** We need to read again if:
2059 ** We have read the entire buffer
2060 ** and we don't have a newline at the end
2061 ** (must be careful about that - we may just have read enough)
2062 */
2063 ajStrSetValidLen(pthis, ilen);
2064 thys = *pthis;
2065
2066 if((jlen == (isize-1)) &&
2067 (ajStrGetCharLast(thys) != '\n'))
2068 {
2069 ajStrSetRes(pthis, ajStrGetRes(thys)+fileBuffSize);
2070 thys = *pthis;
2071 /*ajDebug("more to do: jlen: %d ipos: %d isize: %d ilen: %d "
2072 "Size: %d\n",
2073 jlen, ipos, isize, ilen, ajStrGetRes(thys));*/
2074 ipos += jlen;
2075 buff = ajStrGetuniquePtr(pthis);
2076 isize = ajStrGetRes(thys) - ipos;
2077 /* ajDebug("expand to: ipos: %d isize: %d Size: %d\n",
2078 ipos, isize, ajStrGetRes(thys)); */
2079
2080 }
2081 else
2082 buff = NULL;
2083 }
2084
2085 ajStrSetValidLen(pthis, ilen);
2086
2087 if(ajStrGetCharLast(*pthis) == '\n')
2088 ajStrCutEnd(pthis, 1);
2089
2090 /* PC files have \r\n Macintosh files have just \r : this fixes both */
2091
2092 if(ajStrGetCharLast(*pthis) == '\r')
2093 {
2094 /*ajDebug("Remove carriage-return characters from PC-style files\n");*/
2095 ajStrCutEnd(pthis, 1);
2096 }
2097
2098 ajStrTrimWhite(pthis);
2099
2100 return ajStrGetLen(*pthis);
2101 }
2102
2103
2104
2105
2106 /* @func ajMessExit ***********************************************************
2107 **
2108 ** Delete any static initialised values
2109 **
2110 ** @return [void]
2111 **
2112 ** @release 1.0.0
2113 ** @@
2114 ******************************************************************************/
2115
ajMessExit(void)2116 void ajMessExit(void)
2117 {
2118 AJFREE(messErrMess);
2119 messTableDelete(&messErrorTable);
2120 messTableDelete(&messDebugTestTable);
2121
2122 return;
2123 }
2124
2125
2126
2127
2128 /* @func ajMessExitDebug ******************************************************
2129 **
2130 ** Delete any static initialised values for ajDebug calls
2131 **
2132 ** @return [void]
2133 **
2134 ** @release 6.2.0
2135 ** @@
2136 ******************************************************************************/
2137
ajMessExitDebug(void)2138 void ajMessExitDebug(void)
2139 {
2140 ajFileClose(&messDebugFile);
2141 ajStrDel(&messDebugName);
2142 ajFileClose(&messDebugTestFile);
2143 ajStrDel(&messDebugName);
2144
2145 return;
2146 }
2147
2148
2149
2150
2151 #ifdef AJ_COMPILE_DEPRECATED_BOOK
2152 #endif
2153
2154
2155
2156
2157 #ifdef AJ_COMPILE_DEPRECATED
2158 /* @obsolete ajMessErrorCount
2159 ** @rename ajMessGetCountError
2160 */
2161
ajMessErrorCount(void)2162 __deprecated ajint ajMessErrorCount(void)
2163 {
2164 return errorCount;
2165 }
2166
2167
2168
2169
2170 /* @obsolete ajMessCaughtMessage
2171 ** @rename ajMessGetMessageC
2172 */
2173
ajMessCaughtMessage(void)2174 __deprecated char* ajMessCaughtMessage(void)
2175 {
2176 return messbuf;
2177 }
2178
2179
2180
2181
2182 /* @obsolete ajMessSysErrorText
2183 ** @rename ajMessGetSysmessageC
2184 */
2185
ajMessSysErrorText(void)2186 __deprecated char* ajMessSysErrorText(void)
2187 {
2188 char *mess;
2189
2190 if(errno)
2191 mess = ajFmtString(SYSERR_FORMAT, errno, strerror(errno));
2192 else
2193 mess = ajFmtString(SYSERR_OK, errno, strerror(errno));
2194
2195 /* must make copy - will be used when mess* calls itself */
2196 AJFREE(messErrMess);
2197 messErrMess = ajSysFuncStrdup(mess);
2198
2199 AJFREE(mess);
2200
2201 return messErrMess;
2202 }
2203
2204
2205
2206
2207 /* @obsolete ajDebugFile
2208 ** @rename ajMessGetDebugfile
2209 */
2210
ajDebugFile(void)2211 __deprecated FILE* ajDebugFile(void)
2212 {
2213 return ajMessGetDebugfile();
2214 }
2215 #endif
2216