Fix standalone libtasn1.
[shishi.git] / asn1 / parser_aux.c
blob6f33563fae61ded8b27adbbc0204d829ec7cbfd5
1 /*
2 * Copyright (C) 2000,2001 Fabio Fiorina
4 * This file is part of LIBASN1.
6 * The LIBTASN1 library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <int.h>
22 #include <errors.h>
23 #include "parser_aux.h"
24 #include "der.h"
25 #include "gstr.h"
26 #include "structure.h"
27 #include "element.h"
29 char _asn1_identifierMissing[MAX_NAME_SIZE+1]; /* identifier name not found */
31 /***********************************************/
32 /* Type: list_type */
33 /* Description: type used in the list during */
34 /* the structure creation. */
35 /***********************************************/
36 typedef struct list_struct{
37 node_asn *node;
38 struct list_struct *next;
39 } list_type;
42 /* Pointer to the first element of the list */
43 list_type *firstElement=NULL;
45 /******************************************************/
46 /* Function : _asn1_add_node */
47 /* Description: creates a new NODE_ASN element and */
48 /* puts it in the list pointed by firstElement. */
49 /* Parameters: */
50 /* type: type of the new element (see TYPE_ */
51 /* and CONST_ constants). */
52 /* Return: pointer to the new element. */
53 /******************************************************/
54 node_asn *
55 _asn1_add_node(unsigned int type)
57 list_type *listElement;
58 node_asn *punt;
60 punt=(node_asn *) _asn1_malloc(sizeof(node_asn));
61 if (punt==NULL) return NULL;
63 listElement=(list_type *) _asn1_malloc(sizeof(list_type));
64 if(listElement==NULL){
65 _asn1_free(punt);
66 return NULL;
69 listElement->node=punt;
70 listElement->next=firstElement;
71 firstElement=listElement;
73 punt->left=NULL;
74 punt->name=NULL;
75 punt->type=type;
76 punt->value=NULL;
77 punt->down=NULL;
78 punt->right=NULL;
80 return punt;
83 /******************************************************************/
84 /* Function : _asn1_find_mode */
85 /* Description: searches an element called NAME starting from */
86 /* POINTER. The name is composed by differents */
87 /* identifiers separated by dots.When *POINTER has a */
88 /* name, the first identifier must be the name of */
89 /* *POINTER, otherwise it must be the name of one */
90 /* child of *POINTER. */
91 /* Parameters: */
92 /* pointer: NODE_ASN element pointer. */
93 /* name: null terminated string with the element's name to find.*/
94 /* Return: the searching result. NULL if not find. */
95 /******************************************************************/
96 node_asn *
97 _asn1_find_node(node_asn *pointer,const char *name)
99 node_asn *p;
100 char *n_end,n[MAX_NAME_SIZE+1];
101 const char *n_start;
103 if(pointer == NULL) return NULL;
105 if(name==NULL) return NULL;
107 p=pointer;
108 n_start=name;
110 if(p->name != NULL){ /* has *pointer a name ? */
111 n_end=strchr(n_start,'.'); /* search the first dot */
112 if(n_end){
113 memcpy(n,n_start,n_end-n_start);
114 n[n_end-n_start]=0;
115 n_start=n_end;
116 n_start++;
118 else{
119 _asn1_str_cpy(n,sizeof(n),n_start);
120 n_start=NULL;
123 while(p){
124 if((p->name) && (!strcmp(p->name,n))) break;
125 else p=p->right;
126 } /* while */
128 if(p==NULL) return NULL;
130 else{ /* *pointer doesn't have a name */
131 if(n_start[0]==0)
132 return p;
135 while(n_start){ /* Has the end of NAME been reached? */
136 n_end=strchr(n_start,'.'); /* search the next dot */
137 if(n_end){
138 memcpy(n,n_start,n_end-n_start);
139 n[n_end-n_start]=0;
140 n_start=n_end;
141 n_start++;
143 else{
144 _asn1_str_cpy(n,sizeof(n),n_start);
145 n_start=NULL;
148 if(p->down==NULL) return NULL;
150 p=p->down;
152 /* The identifier "?LAST" indicates the last element
153 in the right chain. */
154 if(!strcmp(n,"?LAST")){
155 if(p==NULL) return NULL;
156 while(p->right) p=p->right;
158 else{ /* no "?LAST" */
159 while(p){
160 if((p->name) && (!strcmp(p->name,n))) break;
161 else p=p->right;
163 if(p==NULL) return NULL;
165 } /* while */
167 return p;
171 /******************************************************************/
172 /* Function : _asn1_set_value */
173 /* Description: sets the field VALUE in a NODE_ASN element. The */
174 /* previus value (if exist) will be lost */
175 /* Parameters: */
176 /* node: element pointer. */
177 /* value: pointer to the value that you want to set. */
178 /* len: character number of value. */
179 /* Return: pointer to the NODE_ASN element. */
180 /******************************************************************/
181 node_asn *
182 _asn1_set_value(node_asn *node,const unsigned char *value,unsigned int len)
185 if(node==NULL) return node;
186 if(node->value){
187 _asn1_free(node->value);
188 node->value=NULL;
190 if(!len) return node;
191 node->value=(unsigned char *) _asn1_malloc(len);
192 if (node->value==NULL) return NULL;
194 memcpy(node->value,value,len);
195 return node;
198 /******************************************************************/
199 /* Function : _asn1_set_name */
200 /* Description: sets the field NAME in a NODE_ASN element. The */
201 /* previus value (if exist) will be lost */
202 /* Parameters: */
203 /* node: element pointer. */
204 /* name: a null terminated string with the name that you want */
205 /* to set. */
206 /* Return: pointer to the NODE_ASN element. */
207 /******************************************************************/
208 node_asn *
209 _asn1_set_name(node_asn *node,const char *name)
211 if(node==NULL) return node;
213 if(node->name){
214 _asn1_free(node->name);
215 node->name=NULL;
218 if(name==NULL) return node;
220 if(strlen(name))
222 node->name=(char *) _asn1_strdup( name);
223 if (node->name==NULL) return NULL;
225 else node->name=NULL;
226 return node;
229 /******************************************************************/
230 /* Function : _asn1_set_right */
231 /* Description: sets the field RIGHT in a NODE_ASN element. */
232 /* Parameters: */
233 /* node: element pointer. */
234 /* right: pointer to a NODE_ASN element that you want be pointed*/
235 /* by NODE. */
236 /* Return: pointer to *NODE. */
237 /******************************************************************/
238 node_asn *
239 _asn1_set_right(node_asn *node,node_asn *right)
241 if(node==NULL) return node;
242 node->right=right;
243 if(right) right->left=node;
244 return node;
247 /******************************************************************/
248 /* Function : _asn1_get_right */
249 /* Description: returns the element pointed by the RIGHT field of */
250 /* a NODE_ASN element. */
251 /* Parameters: */
252 /* node: NODE_ASN element pointer. */
253 /* Return: field RIGHT of NODE. */
254 /******************************************************************/
255 node_asn *
256 _asn1_get_right(node_asn *node)
258 if(node==NULL) return NULL;
259 return node->right;
262 /******************************************************************/
263 /* Function : _asn1_get_last_right */
264 /* Description: return the last element along the right chain. */
265 /* Parameters: */
266 /* node: starting element pointer. */
267 /* Return: pointer to the last element along the right chain. */
268 /******************************************************************/
269 node_asn *
270 _asn1_get_last_right(node_asn *node)
272 node_asn *p;
274 if(node==NULL) return NULL;
275 p=node;
276 while(p->right) p=p->right;
277 return p;
280 /******************************************************************/
281 /* Function : _asn1_set_down */
282 /* Description: sets the field DOWN in a NODE_ASN element. */
283 /* Parameters: */
284 /* node: element pointer. */
285 /* down: pointer to a NODE_ASN element that you want be pointed */
286 /* by NODE. */
287 /* Return: pointer to *NODE. */
288 /******************************************************************/
289 node_asn *
290 _asn1_set_down(node_asn *node,node_asn *down)
292 if(node==NULL) return node;
293 node->down=down;
294 if(down) down->left=node;
295 return node;
298 /******************************************************************/
299 /* Function : _asn1_get_down */
300 /* Description: returns the element pointed by the DOWN field of */
301 /* a NODE_ASN element. */
302 /* Parameters: */
303 /* node: NODE_ASN element pointer. */
304 /* Return: field DOWN of NODE. */
305 /******************************************************************/
306 node_asn *
307 _asn1_get_down(node_asn *node)
309 if(node==NULL) return NULL;
310 return node->down;
313 /******************************************************************/
314 /* Function : _asn1_get_name */
315 /* Description: returns the name of a NODE_ASN element. */
316 /* Parameters: */
317 /* node: NODE_ASN element pointer. */
318 /* Return: a null terminated string. */
319 /******************************************************************/
320 char *
321 _asn1_get_name(node_asn *node)
323 if(node==NULL) return NULL;
324 return node->name;
327 /******************************************************************/
328 /* Function : _asn1_mod_type */
329 /* Description: change the field TYPE of an NODE_ASN element. */
330 /* The new value is the old one | (bitwise or) the */
331 /* paramener VALUE. */
332 /* Parameters: */
333 /* node: NODE_ASN element pointer. */
334 /* value: the integer value that must be or-ed with the current */
335 /* value of field TYPE. */
336 /* Return: NODE pointer. */
337 /******************************************************************/
338 node_asn *
339 _asn1_mod_type(node_asn *node,unsigned int value)
341 if(node==NULL) return node;
342 node->type|=value;
343 return node;
347 /******************************************************************/
348 /* Function : _asn1_remove_node */
349 /* Description: gets free the memory allocated for an NODE_ASN */
350 /* element (not the elements pointed by it). */
351 /* Parameters: */
352 /* node: NODE_ASN element pointer. */
353 /******************************************************************/
354 void
355 _asn1_remove_node(node_asn *node)
357 if(node==NULL) return;
359 if (node->name!=NULL)
360 _asn1_free(node->name);
361 if (node->value!=NULL)
362 _asn1_free(node->value);
363 _asn1_free(node);
366 /******************************************************************/
367 /* Function : _asn1_find_up */
368 /* Description: return the father of the NODE_ASN element. */
369 /* Parameters: */
370 /* node: NODE_ASN element pointer. */
371 /* Return: Null if not found. */
372 /******************************************************************/
373 node_asn *
374 _asn1_find_up(node_asn *node)
376 node_asn *p;
378 if(node==NULL) return NULL;
380 p=node;
382 while((p->left!=NULL) && (p->left->right==p)) p=p->left;
384 return p->left;
387 /******************************************************************/
388 /* Function : _asn1_delete_list */
389 /* Description: deletes the list elements (not the elements */
390 /* pointed by them). */
391 /******************************************************************/
392 void
393 _asn1_delete_list(void)
395 list_type *listElement;
397 while(firstElement){
398 listElement=firstElement;
399 firstElement=firstElement->next;
400 _asn1_free(listElement);
404 /******************************************************************/
405 /* Function : _asn1_delete_list_and nodes */
406 /* Description: deletes the list elements and the elements */
407 /* pointed by them. */
408 /******************************************************************/
409 void
410 _asn1_delete_list_and_nodes(void)
412 list_type *listElement;
414 while(firstElement){
415 listElement=firstElement;
416 firstElement=firstElement->next;
417 _asn1_remove_node(listElement->node);
418 _asn1_free(listElement);
423 char *
424 _asn1_ltostr(long v,char *str)
426 long d,r;
427 char temp[20];
428 int count,k,start;
430 if(v<0){
431 str[0]='-';
432 start=1;
433 v=-v;
435 else start=0;
437 count=0;
439 d=v/10;
440 r=v-d*10;
441 temp[start+count]='0'+(char)r;
442 count++;
443 v=d;
444 }while(v);
446 for(k=0;k<count;k++) str[k+start]=temp[start+count-k-1];
447 str[count+start]=0;
448 return str;
452 /******************************************************************/
453 /* Function : _asn1_change_integer_value */
454 /* Description: converts into DER coding the value assign to an */
455 /* INTEGER constant. */
456 /* Parameters: */
457 /* node: root of an ASN1element. */
458 /* Return: */
459 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
460 /* otherwise ASN1_SUCCESS */
461 /******************************************************************/
462 asn1_retCode
463 _asn1_change_integer_value(ASN1_TYPE node)
465 node_asn *p;
466 unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
467 unsigned char val2[SIZEOF_UNSIGNED_LONG_INT+1];
468 int len;
470 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
472 p=node;
473 while(p){
474 if((type_field(p->type)==TYPE_INTEGER) && (p->type&CONST_ASSIGN)){
475 if(p->value){
476 _asn1_convert_integer(p->value,val,sizeof(val), &len);
477 _asn1_octet_der(val,len,val2,&len);
478 _asn1_set_value(p,val2,len);
482 if(p->down){
483 p=p->down;
485 else{
486 if(p==node) p=NULL;
487 else if(p->right) p=p->right;
488 else{
489 while(1){
490 p=_asn1_find_up(p);
491 if(p==node){
492 p=NULL;
493 break;
495 if(p->right){
496 p=p->right;
497 break;
504 return ASN1_SUCCESS;
508 /******************************************************************/
509 /* Function : _asn1_expand_object_id */
510 /* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
511 /* Parameters: */
512 /* node: root of an ASN1 element. */
513 /* Return: */
514 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
515 /* otherwise ASN1_SUCCESS */
516 /******************************************************************/
517 asn1_retCode
518 _asn1_expand_object_id(ASN1_TYPE node)
520 node_asn *p,*p2,*p3,*p4,*p5;
521 char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
522 int move;
524 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
526 _asn1_str_cpy(name_root, sizeof(name_root), node->name);
528 p=node;
529 move=DOWN;
531 while(!((p==node) && (move==UP))){
532 if(move!=UP){
533 if((type_field(p->type)==TYPE_OBJECT_ID) && (p->type&CONST_ASSIGN)){
534 p2=p->down;
535 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
536 if(p2->value && !isdigit(p2->value[0])){
537 _asn1_str_cpy(name2, sizeof(name2), name_root);
538 _asn1_str_cat(name2, sizeof(name2), ".");
539 _asn1_str_cat(name2, sizeof(name2), p2->value);
540 p3=_asn1_find_node(node,name2);
541 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
542 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
543 _asn1_set_down(p,p2->right);
544 _asn1_remove_node(p2);
545 p2=p;
546 p4=p3->down;
547 while(p4){
548 if(type_field(p4->type)==TYPE_CONSTANT){
549 p5=_asn1_add_node_only(TYPE_CONSTANT);
550 _asn1_set_name(p5,p4->name);
551 _asn1_set_value(p5,p4->value,strlen(p4->value)+1);
552 if(p2==p){
553 _asn1_set_right(p5,p->down);
554 _asn1_set_down(p,p5);
556 else{
557 _asn1_set_right(p5,p2->right);
558 _asn1_set_right(p2,p5);
560 p2=p5;
562 p4=p4->right;
564 move=DOWN;
565 continue;
569 move=DOWN;
571 else move=RIGHT;
573 if(move==DOWN){
574 if(p->down) p=p->down;
575 else move=RIGHT;
578 if(p==node) {move=UP; continue;}
580 if(move==RIGHT){
581 if(p->right) p=p->right;
582 else move=UP;
584 if(move==UP) p=_asn1_find_up(p);
588 /*******************************/
589 /* expand DEFAULT */
590 /*******************************/
591 p=node;
592 move=DOWN;
594 while(!((p==node) && (move==UP))){
595 if(move!=UP){
596 if((type_field(p->type)==TYPE_OBJECT_ID) &&
597 (p->type&CONST_DEFAULT)){
598 p2=p->down;
599 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
600 _asn1_str_cpy(name2, sizeof(name2), name_root);
601 _asn1_str_cat(name2, sizeof(name2), ".");
602 _asn1_str_cat(name2, sizeof(name2), p2->value);
603 p3=_asn1_find_node(node,name2);
604 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
605 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
606 p4=p3->down;
607 name2[0]=0;
608 while(p4){
609 if(type_field(p4->type)==TYPE_CONSTANT){
610 if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
611 _asn1_str_cat(name2,sizeof(name2),p4->value);
613 p4=p4->right;
615 _asn1_set_value(p2,name2,strlen(name2)+1);
618 move=DOWN;
620 else move=RIGHT;
622 if(move==DOWN){
623 if(p->down) p=p->down;
624 else move=RIGHT;
627 if(p==node) {move=UP; continue;}
629 if(move==RIGHT){
630 if(p->right) p=p->right;
631 else move=UP;
633 if(move==UP) p=_asn1_find_up(p);
636 return ASN1_SUCCESS;
640 /******************************************************************/
641 /* Function : _asn1_type_set_config */
642 /* Description: sets the CONST_SET and CONST_NOT_USED properties */
643 /* in the fields of the SET elements. */
644 /* Parameters: */
645 /* node: root of an ASN1 element. */
646 /* Return: */
647 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
648 /* otherwise ASN1_SUCCESS */
649 /******************************************************************/
650 asn1_retCode
651 _asn1_type_set_config(ASN1_TYPE node)
653 node_asn *p,*p2;
654 int move;
656 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
658 p=node;
659 move=DOWN;
661 while(!((p==node) && (move==UP))){
662 if(move!=UP){
663 if(type_field(p->type)==TYPE_SET){
664 p2=p->down;
665 while(p2){
666 if(type_field(p2->type)!=TYPE_TAG)
667 p2->type|=CONST_SET|CONST_NOT_USED;
668 p2=p2->right;
671 move=DOWN;
673 else move=RIGHT;
675 if(move==DOWN){
676 if(p->down) p=p->down;
677 else move=RIGHT;
680 if(p==node) {move=UP; continue;}
682 if(move==RIGHT){
683 if(p->right) p=p->right;
684 else move=UP;
686 if(move==UP) p=_asn1_find_up(p);
689 return ASN1_SUCCESS;
693 /******************************************************************/
694 /* Function : _asn1_check_identifier */
695 /* Description: checks the definitions of all the identifiers */
696 /* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
697 /* The _asn1_identifierMissing global variable is filled if */
698 /* necessary. */
699 /* Parameters: */
700 /* node: root of an ASN1 element. */
701 /* Return: */
702 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
703 /* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
704 /* otherwise ASN1_SUCCESS */
705 /******************************************************************/
706 asn1_retCode
707 _asn1_check_identifier(ASN1_TYPE node)
709 node_asn *p,*p2;
710 char name2[MAX_NAME_SIZE*2+2];
712 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
714 p=node;
715 while(p){
716 if(type_field(p->type)==TYPE_IDENTIFIER){
717 _asn1_str_cpy(name2, sizeof(name2), node->name);
718 _asn1_str_cat(name2, sizeof(name2), ".");
719 _asn1_str_cat(name2, sizeof(name2), p->value);
720 p2=_asn1_find_node(node,name2);
721 if(p2==NULL){
722 strcpy(_asn1_identifierMissing,p->value);
723 return ASN1_IDENTIFIER_NOT_FOUND;
726 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
727 (p->type&CONST_DEFAULT)){
728 p2=p->down;
729 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
730 _asn1_str_cpy(name2, sizeof(name2), node->name);
731 _asn1_str_cat(name2, sizeof(name2), ".");
732 _asn1_str_cat(name2, sizeof(name2), p2->value);
733 strcpy(_asn1_identifierMissing,p2->value);
734 p2=_asn1_find_node(node,name2);
735 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
736 !(p2->type&CONST_ASSIGN))
737 return ASN1_IDENTIFIER_NOT_FOUND;
738 else
739 _asn1_identifierMissing[0]=0;
742 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
743 (p->type&CONST_ASSIGN)){
744 p2=p->down;
745 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
746 if(p2->value && !isdigit(p2->value[0])){
747 _asn1_str_cpy(name2, sizeof(name2), node->name);
748 _asn1_str_cat(name2, sizeof(name2), ".");
749 _asn1_str_cat(name2, sizeof(name2), p2->value);
750 strcpy(_asn1_identifierMissing,p2->value);
751 p2=_asn1_find_node(node,name2);
752 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
753 !(p2->type&CONST_ASSIGN))
754 return ASN1_IDENTIFIER_NOT_FOUND;
755 else
756 _asn1_identifierMissing[0]=0;
761 if(p->down){
762 p=p->down;
764 else if(p->right) p=p->right;
765 else{
766 while(1){
767 p=_asn1_find_up(p);
768 if(p==node){
769 p=NULL;
770 break;
772 if(p->right){
773 p=p->right;
774 break;
780 return ASN1_SUCCESS;
784 /******************************************************************/
785 /* Function : _asn1_set_default_tag */
786 /* Description: sets the default IMPLICIT or EXPLICIT property in */
787 /* the tagged elements that don't have this declaration. */
788 /* Parameters: */
789 /* node: pointer to a DEFINITIONS element. */
790 /* Return: */
791 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
792 /* a DEFINITIONS element, */
793 /* otherwise ASN1_SUCCESS */
794 /******************************************************************/
795 asn1_retCode
796 _asn1_set_default_tag(ASN1_TYPE node)
798 node_asn *p;
800 if((node==NULL) || (type_field(node->type)!=TYPE_DEFINITIONS))
801 return ASN1_ELEMENT_NOT_FOUND;
803 p=node;
804 while(p){
805 if((type_field(p->type)==TYPE_TAG) &&
806 !(p->type&CONST_EXPLICIT) &&
807 !(p->type&CONST_IMPLICIT)){
808 if(node->type&CONST_EXPLICIT) p->type|=CONST_EXPLICIT;
809 else p->type|=CONST_IMPLICIT;
812 if(p->down){
813 p=p->down;
815 else if(p->right) p=p->right;
816 else{
817 while(1){
818 p=_asn1_find_up(p);
819 if(p==node){
820 p=NULL;
821 break;
823 if(p->right){
824 p=p->right;
825 break;
831 return ASN1_SUCCESS;
836 static const char*
837 parse_version_number( const char *s, int *number )
839 int val = 0;
841 if( *s == '0' && isdigit(s[1]) )
842 return NULL; /* leading zeros are not allowed */
843 for ( ; isdigit(*s); s++ ) {
844 val *= 10;
845 val += *s - '0';
847 *number = val;
848 return val < 0? NULL : s;
851 /* The parse version functions were copied from libgcrypt.
853 static const char *
854 parse_version_string( const char *s, int *major, int *minor, int *micro )
856 s = parse_version_number( s, major );
857 if( !s || *s != '.' )
858 return NULL;
859 s++;
860 s = parse_version_number( s, minor );
861 if( !s || *s != '.' )
862 return NULL;
863 s++;
864 s = parse_version_number( s, micro );
865 if( !s )
866 return NULL;
867 return s; /* patchlevel */
871 * asn1_check_version - This function checks the library's version
872 * @req_version: the version to check
874 * Check that the the version of the library is at minimum the requested one
875 * and return the version string; return NULL if the condition is not
876 * satisfied. If a NULL is passed to this function, no check is done,
877 * but the version string is simply returned.
880 const char *
881 asn1_check_version( const char *req_version )
883 const char *ver = LIBTASN1_VERSION;
884 int my_major, my_minor, my_micro;
885 int rq_major, rq_minor, rq_micro;
886 const char *my_plvl, *rq_plvl;
888 if ( !req_version )
889 return ver;
891 my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
892 if ( !my_plvl )
893 return NULL; /* very strange our own version is bogus */
894 rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
895 &rq_micro );
896 if ( !rq_plvl )
897 return NULL; /* req version string is invalid */
899 if ( my_major > rq_major
900 || (my_major == rq_major && my_minor > rq_minor)
901 || (my_major == rq_major && my_minor == rq_minor
902 && my_micro > rq_micro)
903 || (my_major == rq_major && my_minor == rq_minor
904 && my_micro == rq_micro
905 && strcmp( my_plvl, rq_plvl ) >= 0) ) {
906 return ver;
908 return NULL;