Initial revision


git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@2 59561ff5-6e30-0410-9f3c-9617f08c8826
diff --git a/libasn1fix/Makefile.am b/libasn1fix/Makefile.am
new file mode 100644
index 0000000..0e52b4f
--- /dev/null
+++ b/libasn1fix/Makefile.am
@@ -0,0 +1,36 @@
+
+
+AM_CFLAGS = @ADD_CFLAGS@
+AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
+
+noinst_LTLIBRARIES = libasn1fix.la
+
+libasn1fix_la_LDFLAGS = -all-static
+libasn1fix_la_SOURCES =				\
+	asn1fix.c asn1fix.h			\
+	asn1fix_internal.h			\
+	asn1fix_misc.c asn1fix_misc.h		\
+	asn1fix_value.c asn1fix_value.h		\
+	asn1fix_compat.c asn1fix_compat.h	\
+	asn1fix_constr.c asn1fix_constr.h	\
+	asn1fix_cstring.c asn1fix_cstring.h	\
+	asn1fix_retrieve.c asn1fix_retrieve.h	\
+	asn1fix_bitstring.c asn1fix_bitstring.h	\
+	asn1fix_integer.c asn1fix_integer.h	\
+	asn1fix_dereft.c asn1fix_dereft.h	\
+	asn1fix_derefv.c asn1fix_derefv.h	\
+	asn1fix_export.c asn1fix_export.h	\
+	asn1fix_param.c asn1fix_param.h		\
+	asn1fix_class.c asn1fix_class.h		\
+	asn1fix_tags.c asn1fix_tags.h		\
+	asn1fix_enum.c asn1fix_enum.h
+libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
+
+check_PROGRAMS = check_fixer
+
+LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
+DEPENDENCIES = ${LDADD} 
+
+TESTS_ENVIRONMENT= ./check_fixer
+TESTS = ${top_srcdir}/tests/*.asn1
+## TESTS = ${check_PROGRAMS}	# This is an alternate form of testing
diff --git a/libasn1fix/Makefile.in b/libasn1fix/Makefile.in
new file mode 100644
index 0000000..8d919c2
--- /dev/null
+++ b/libasn1fix/Makefile.in
@@ -0,0 +1,454 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+ADD_CFLAGS = @ADD_CFLAGS@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+CC = @CC@
+CONFIGURE_DEPENDS = @CONFIGURE_DEPENDS@
+CPP = @CPP@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LEX = @LEX@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PATH = @PATH@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+YACC = @YACC@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+
+AM_CFLAGS = @ADD_CFLAGS@
+AM_CPPFLAGS = -I${top_srcdir}/libasn1parser
+
+noinst_LTLIBRARIES = libasn1fix.la
+
+libasn1fix_la_LDFLAGS = -all-static
+libasn1fix_la_SOURCES = \
+	asn1fix.c asn1fix.h			\
+	asn1fix_internal.h			\
+	asn1fix_misc.c asn1fix_misc.h		\
+	asn1fix_value.c asn1fix_value.h		\
+	asn1fix_compat.c asn1fix_compat.h	\
+	asn1fix_constr.c asn1fix_constr.h	\
+	asn1fix_cstring.c asn1fix_cstring.h	\
+	asn1fix_retrieve.c asn1fix_retrieve.h	\
+	asn1fix_bitstring.c asn1fix_bitstring.h	\
+	asn1fix_integer.c asn1fix_integer.h	\
+	asn1fix_dereft.c asn1fix_dereft.h	\
+	asn1fix_derefv.c asn1fix_derefv.h	\
+	asn1fix_export.c asn1fix_export.h	\
+	asn1fix_param.c asn1fix_param.h		\
+	asn1fix_class.c asn1fix_class.h		\
+	asn1fix_tags.c asn1fix_tags.h		\
+	asn1fix_enum.c asn1fix_enum.h
+
+libasn1fix_la_LIBADD = ${top_builddir}/libasn1parser/libasn1parser.la
+
+check_PROGRAMS = check_fixer
+
+LDADD = ${noinst_LTLIBRARIES} ${libasn1fix_la_LIBADD}
+DEPENDENCIES = ${LDADD} 
+
+TESTS_ENVIRONMENT = ./check_fixer
+TESTS = ${top_srcdir}/tests/*.asn1
+subdir = libasn1fix
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+libasn1fix_la_DEPENDENCIES = \
+	${top_builddir}/libasn1parser/libasn1parser.la
+am_libasn1fix_la_OBJECTS = asn1fix.lo asn1fix_misc.lo asn1fix_value.lo \
+	asn1fix_compat.lo asn1fix_constr.lo asn1fix_cstring.lo \
+	asn1fix_retrieve.lo asn1fix_bitstring.lo asn1fix_integer.lo \
+	asn1fix_dereft.lo asn1fix_derefv.lo asn1fix_export.lo \
+	asn1fix_param.lo asn1fix_class.lo asn1fix_tags.lo \
+	asn1fix_enum.lo
+libasn1fix_la_OBJECTS = $(am_libasn1fix_la_OBJECTS)
+check_PROGRAMS = check_fixer$(EXEEXT)
+check_fixer_SOURCES = check_fixer.c
+check_fixer_OBJECTS = check_fixer.$(OBJEXT)
+check_fixer_LDADD = $(LDADD)
+check_fixer_DEPENDENCIES = libasn1fix.la \
+	${top_builddir}/libasn1parser/libasn1parser.la
+check_fixer_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/asn1fix.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_bitstring.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_class.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_compat.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_constr.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_cstring.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_dereft.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_derefv.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_enum.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_export.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_integer.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_misc.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_param.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_retrieve.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_tags.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/asn1fix_value.Plo \
+@AMDEP_TRUE@	$(DEPDIR)/check_fixer.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+	$(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(libasn1fix_la_SOURCES) check_fixer.c
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(libasn1fix_la_SOURCES) check_fixer.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu  libasn1fix/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in  $(top_builddir)/config.status
+	cd $(top_builddir) && \
+	  CONFIG_HEADERS= CONFIG_LINKS= \
+	  CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+	-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+libasn1fix.la: $(libasn1fix_la_OBJECTS) $(libasn1fix_la_DEPENDENCIES) 
+	$(LINK)  $(libasn1fix_la_LDFLAGS) $(libasn1fix_la_OBJECTS) $(libasn1fix_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	-test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS)
+check_fixer$(EXEEXT): $(check_fixer_OBJECTS) $(check_fixer_DEPENDENCIES) 
+	@rm -f check_fixer$(EXEEXT)
+	$(LINK) $(check_fixer_LDFLAGS) $(check_fixer_OBJECTS) $(check_fixer_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_bitstring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_class.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_compat.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_constr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_cstring.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_dereft.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_derefv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_enum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_export.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_integer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_param.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_retrieve.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_tags.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/asn1fix_value.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/check_fixer.Po@am__quote@
+
+distclean-depend:
+	-rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+	  || etags $(ETAGS_ARGS) $$tags  $$unique $(LISP)
+
+GTAGS:
+	here=`CDPATH=: && cd $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+check-TESTS: $(TESTS)
+	@failed=0; all=0; xfail=0; xpass=0; \
+	srcdir=$(srcdir); export srcdir; \
+	list='$(TESTS)'; \
+	if test -n "$$list"; then \
+	  for tst in $$list; do \
+	    if test -f ./$$tst; then dir=./; \
+	    elif test -f $$tst; then dir=; \
+	    else dir="$(srcdir)/"; fi; \
+	    if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+	        xpass=`expr $$xpass + 1`; \
+	        failed=`expr $$failed + 1`; \
+	        echo "XPASS: $$tst"; \
+	      ;; \
+	      *) \
+	        echo "PASS: $$tst"; \
+	      ;; \
+	      esac; \
+	    elif test $$? -ne 77; then \
+	      all=`expr $$all + 1`; \
+	      case " $(XFAIL_TESTS) " in \
+	      *" $$tst "*) \
+	        xfail=`expr $$xfail + 1`; \
+	        echo "XFAIL: $$tst"; \
+	      ;; \
+	      *) \
+	        failed=`expr $$failed + 1`; \
+	        echo "FAIL: $$tst"; \
+	      ;; \
+	      esac; \
+	    fi; \
+	  done; \
+	  if test "$$failed" -eq 0; then \
+	    if test "$$xfail" -eq 0; then \
+	      banner="All $$all tests passed"; \
+	    else \
+	      banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
+	    fi; \
+	  else \
+	    if test "$$xpass" -eq 0; then \
+	      banner="$$failed of $$all tests failed"; \
+	    else \
+	      banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
+	    fi; \
+	  fi; \
+	  dashes=`echo "$$banner" | sed s/./=/g`; \
+	  echo "$$dashes"; \
+	  echo "$$banner"; \
+	  echo "$$dashes"; \
+	  test "$$failed" -eq 0; \
+	fi
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+	@for file in $(DISTFILES); do \
+	  if test -f $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    $(mkinstalldirs) "$(distdir)/$$dir"; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    cp -pR $$d/$$file $(distdir) \
+	    || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+	distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-TESTS check-am clean \
+	clean-checkPROGRAMS clean-generic clean-libtool \
+	clean-noinstLTLIBRARIES distclean distclean-compile \
+	distclean-depend distclean-generic distclean-libtool \
+	distclean-tags distdir dvi dvi-am info info-am install \
+	install-am install-data install-data-am install-exec \
+	install-exec-am install-info install-info-am install-man \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	tags uninstall uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libasn1fix/asn1fix.c b/libasn1fix/asn1fix.c
new file mode 100644
index 0000000..af11099
--- /dev/null
+++ b/libasn1fix/asn1fix.c
@@ -0,0 +1,354 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#include "asn1fix.h"
+#include "asn1fix_internal.h"
+
+/* Print everything to stderr */
+static void _default_error_logger(int _severity, const char *fmt, ...);
+
+/*
+ * Internal check functions.
+ */
+static int asn1f_fix_module(arg_t *arg);
+static int asn1f_fix_simple(arg_t *arg);	/* For INTEGER/ENUMERATED */
+static int asn1f_fix_constructed(arg_t *arg);	/* For SEQUENCE/SET/CHOICE */
+static int asn1f_fix_constraints(arg_t *arg);	/* For subtype constraints */
+
+
+/*
+ * Scan every module defined here in search for inconsistences.
+ */
+int
+asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
+		error_logger_f error_logger) {
+	arg_t arg;
+	int fatals = 0;
+	int warnings = 0;
+
+	/*
+	 * Check validity of arguments.
+	 */
+	if(asn == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * If errors handler is not specified, default to internal one.
+	 */
+	if(error_logger == 0) {
+		error_logger = _default_error_logger;
+	}
+
+	memset(&arg, 0, sizeof(arg));
+	arg.asn = asn;
+	arg.eh = error_logger;
+
+	if(flags & A1F_DEBUG) {
+		arg.debug = arg.eh;
+		arg.debug(-1, "Called %s() with flags %d", __func__, flags);
+		flags &= ~A1F_DEBUG;
+	}
+
+	/*
+	 * Check that we haven't missed an unknown flag.
+	 */
+	if(flags) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * Process each module in the list.
+	 */
+	TQ_FOR(arg.mod, &(asn->modules), mod_next) {
+		int ret = asn1f_fix_module(&arg);
+		/*
+		 * These lines are used for illustration purposes.
+		 * RET2RVAL() is used everywhere else.
+		 */
+		if(ret == -1) fatals++;
+		if(ret == 1) warnings++;
+	}
+
+	/*
+	 * Compute a return value.
+	 */
+	return fatals?-1:warnings?1:0;
+}
+
+/*
+ * Check the internals of a single module.
+ */
+static int
+asn1f_fix_module(arg_t *arg) {
+	asn1p_expr_t *expr;
+	int rvalue = 0;
+
+	switch((arg->mod->module_flags
+	& (MSF_EXPLICIT_TAGS | MSF_IMPLICIT_TAGS | MSF_AUTOMATIC_TAGS))) {
+	case MSF_NOFLAGS:
+	case MSF_EXPLICIT_TAGS:
+	case MSF_IMPLICIT_TAGS:
+	case MSF_AUTOMATIC_TAGS:
+		break;
+	default:
+		FATAL("Module %s defined with ambiguous global tagging mode",
+			arg->mod->Identifier);
+		RET2RVAL(-1, rvalue);
+	}
+
+	/*
+	 * Do various non-recursive transformations.
+	 * Order is not important.
+	 */
+	TQ_FOR(expr, &(arg->mod->members), next) {
+		int ret;
+		arg->expr = expr;
+
+		if(expr->meta_type == AMT_PARAMTYPE)
+			/* Do not process the parametrized type just yet */
+			continue;
+
+		DEBUG("=== Now processing \"%s\" at line %d ===",
+			expr->Identifier, expr->_lineno);
+		assert(expr->meta_type != AMT_INVALID);
+
+		/*
+		 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * 2.[234] Process SEQUENCE/SET/CHOICE types.
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * 2.5.4
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * 2.5.5
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * Resolve references in constraints.
+		 */
+		ret = asn1f_recurse_expr(arg, asn1f_fix_constraints);
+		RET2RVAL(ret, rvalue);
+
+		/*
+		 * 6. INTEGER value processed at 2.5.4.
+		 */
+
+		/*
+		 * Make sure everybody's behaving well.
+		 */
+		assert(arg->expr == expr);
+	}
+
+	/*
+	 * 5. Automatic tagging
+	 */
+	TQ_FOR(expr, &(arg->mod->members), next) {
+		int ret;
+
+		arg->expr = expr;
+
+		ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
+		RET2RVAL(ret, rvalue);
+
+		assert(arg->expr == expr);
+	}
+
+	/*
+	 * 8. fix BIT STRING
+	 * 9. fix spaces in cstrings
+	 */
+	TQ_FOR(expr, &(arg->mod->members), next) {
+		int ret;
+		arg->expr = expr;
+
+		ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
+		RET2RVAL(ret, rvalue);
+
+		ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
+		RET2RVAL(ret, rvalue);
+
+		assert(arg->expr == expr);
+	}
+
+	/*
+	 * ... Check for tags distinctness.
+	 */
+	TQ_FOR(expr, &(arg->mod->members), next) {
+		int ret;
+		arg->expr = expr;
+
+		ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
+		RET2RVAL(ret, rvalue);
+
+		assert(arg->expr == expr);
+	}
+
+	return rvalue;
+}
+
+
+static int
+asn1f_fix_simple(arg_t *arg) {
+	int rvalue = 0;
+	int ret;
+
+	ret = asn1f_fix_enum(arg);
+	RET2RVAL(ret, rvalue);
+
+	ret = asn1f_fix_integer(arg);
+	RET2RVAL(ret, rvalue);
+
+	return rvalue;
+}
+
+static int
+asn1f_fix_constructed(arg_t *arg) {
+	int rvalue = 0;
+	int ret;
+
+	switch(arg->expr->expr_type) {
+	case ASN_CONSTR_SEQUENCE:
+	case ASN_CONSTR_SET:
+	case ASN_CONSTR_CHOICE:
+		break;
+	default:
+		return 0;
+	}
+
+	/* Check identifier distinctness */
+	ret = asn1f_check_unique_expr(arg, NULL);
+	RET2RVAL(ret, rvalue);
+
+	/* Fix extensibility */
+	ret = asn1f_fix_constr_ext(arg);
+	RET2RVAL(ret, rvalue);
+
+	/* Fix tagging */
+	ret = asn1f_fix_constr_tag(arg);
+	RET2RVAL(ret, rvalue);
+
+	return rvalue;
+}
+
+static int
+_constraint_value_resolve(arg_t *arg, asn1p_value_t **value) {
+	asn1p_expr_t expr;
+	asn1p_expr_t *tmp_expr;
+	asn1p_module_t *tmp_mod;
+	asn1p_module_t *mod_r = NULL;
+	int rvalue = 0;
+	int ret;
+
+	tmp_expr = asn1f_lookup_symbol(arg, (*value)->value.reference, &mod_r);
+	if(tmp_expr == NULL) {
+		FATAL("Cannot find symbol %s "
+			"used in %s subtype constraint at line %d",
+			asn1f_printable_reference((*value)->value.reference),
+			arg->expr->Identifier, arg->expr->_lineno);
+		assert((*value)->type == ATV_REFERENCED);
+		return -1;
+	}
+
+	memset(&expr, 0, sizeof(expr));
+	expr.meta_type = tmp_expr->meta_type;
+	expr.expr_type = tmp_expr->expr_type;
+	expr.Identifier = tmp_expr->Identifier;
+	expr.value = *value;
+	tmp_expr = arg->expr;
+	tmp_mod = arg->mod;
+	arg->expr = &expr;
+	arg->mod = mod_r;
+	ret = asn1f_fix_dereference_values(arg);
+	RET2RVAL(ret, rvalue);
+	arg->expr = tmp_expr;
+	arg->mod = tmp_mod;
+	assert(expr.value);
+	*value = expr.value;
+
+	return rvalue;
+}
+
+static int
+_resolve_constraints(arg_t *arg, asn1p_constraint_t *ct) {
+	int rvalue = 0;
+	int ret;
+	int el;
+
+	/* Don't touch information object classes */
+	if(ct->type == ACT_CT_WCOMP
+	|| ct->type == ACT_CT_WCOMPS
+	|| ct->type == ACT_CA_CRC)
+		return 0;
+
+	if(ct->value && ct->value->type == ATV_REFERENCED) {
+		ret = _constraint_value_resolve(arg, &ct->value);
+		RET2RVAL(ret, rvalue);
+	}
+	if(ct->range_start && ct->range_start->type == ATV_REFERENCED) {
+		ret = _constraint_value_resolve(arg, &ct->range_start);
+		RET2RVAL(ret, rvalue);
+	}
+	if(ct->range_stop && ct->range_stop->type == ATV_REFERENCED) {
+		ret = _constraint_value_resolve(arg, &ct->range_stop);
+		RET2RVAL(ret, rvalue);
+	}
+
+	for(el = 0; el < ct->el_count; el++) {
+		ret = _resolve_constraints(arg, ct->elements[el]);
+		RET2RVAL(ret, rvalue);
+	}
+
+	return rvalue;
+}
+
+static int
+asn1f_fix_constraints(arg_t *arg) {
+	int rvalue = 0;
+	int ret;
+
+	if(arg->expr->constraints) {
+		ret = _resolve_constraints(arg, arg->expr->constraints);
+		RET2RVAL(ret, rvalue);
+	}
+
+	return rvalue;
+}
+
+/*
+ * Print everything to stderr
+ */
+static void
+_default_error_logger(int _severity, const char *fmt, ...) {
+	va_list ap;
+	char *pfx = "";
+
+	switch(_severity) {
+	case -1: pfx = "DEBUG: "; break;
+	case 0: pfx = "WARNING: "; break;
+	case 1: pfx = "FATAL: "; break;
+	}
+	
+	fprintf(stderr, "%s", pfx);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
diff --git a/libasn1fix/asn1fix.h b/libasn1fix/asn1fix.h
new file mode 100644
index 0000000..4847330
--- /dev/null
+++ b/libasn1fix/asn1fix.h
@@ -0,0 +1,30 @@
+/*
+ * This is the public interface for the processor (fixer) of the ASN.1 tree
+ * produced by the libasn1parser.
+ */
+#ifndef	ASN1FIX_H
+#define	ASN1FIX_H
+
+#include <asn1parser.h>
+
+/*
+ * Operation flags for the function below.
+ */
+enum asn1f_flags {
+	A1F_NOFLAGS,
+	A1F_DEBUG,	/* Print debugging output using (_is_fatal = -1) */
+};
+
+/*
+ * Perform a set of semantics checks, transformations and small fixes
+ * on the given tree.
+ * RETURN VALUES:
+ * 	-1:	Some fatal problems were encountered.
+ *	 0:	No inconsistencies were found.
+ *	 1:	Some warnings were issued, but no fatal problems encountered.
+ */
+int asn1f_process(asn1p_t *_asn,
+	enum asn1f_flags,
+	void (*error_log_callback)(int _severity, const char *fmt, ...));
+
+#endif	/* ASN1FIX_H */
diff --git a/libasn1fix/asn1fix_bitstring.c b/libasn1fix/asn1fix_bitstring.c
new file mode 100644
index 0000000..0d3961d
--- /dev/null
+++ b/libasn1fix/asn1fix_bitstring.c
@@ -0,0 +1,230 @@
+#include "asn1fix_internal.h"
+
+int asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype);
+static void asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value);
+static int asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype);
+
+int
+asn1f_fix_bit_string(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	int r_value = 0;
+	int ret;
+
+	if(expr->meta_type == AMT_VALUE) {
+		asn1p_expr_t *ttype;
+
+		DEBUG("%s(%s) for line %d", __func__,
+			expr->Identifier, expr->_lineno);
+
+		ttype = asn1f_find_terminal_type(arg, expr, 0);
+		if(ttype && ttype->expr_type == ASN_BASIC_BIT_STRING) {
+			ret = asn1f_fix_bit_string_value(arg, ttype);
+			RET2RVAL(ret, r_value);
+		}
+	}
+
+	return r_value;
+}
+
+int
+asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype) {
+	asn1p_expr_t *expr = arg->expr;
+	int r_value = 0;
+
+	DEBUG("%s(%s) for line %d", __func__,
+		expr->Identifier, expr->_lineno);
+
+	switch(expr->value->type) {
+	case ATV_UNPARSED:
+		/*
+		 * Most definitely we have something like
+		 * 	value BitStringType1 ::= { a, b, c }
+		 * which could not be parsed by the LALR parser, mostly
+		 * because it requires knowledge about BitStringType1
+		 * during the parsing. So, here's a little hack: we create
+		 * a buffer containing the full specification of a module,
+		 * which contains some pre-defined INTEGER type with the
+		 * opaque definition "{ a, b, c }" from the bit string.
+		 */
+		if(asn1f_BS_unparsed_convert(arg, expr->value, ttype)) {
+			r_value = -1;
+			break;
+		}
+		/* Fall through: remove trailing zero bits */
+	case ATV_BITVECTOR:
+		asn1f_BS_remove_trailing_zero_bits(expr->value);
+		break;
+	default:
+		break;
+	}
+
+	return r_value;
+}
+
+static void
+asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value) {
+	int lmfb = -1;	/* Last meaningful byte position */
+	int bits;	/* Number of bits in the BIT STRING value */
+	int b;
+
+	assert(value->type == ATV_BITVECTOR);
+
+	bits = value->value.binary_vector.size_in_bits;
+	/*
+	 * Figure out the rightmost meaningful byte.
+	 */
+	for(b = 0; b < ((bits + 7) >> 3); b++) {
+		uint8_t uc = value->value.binary_vector.bits[b];
+		if(uc && b > lmfb)
+			lmfb = b;
+	}
+	if(lmfb == -1) {
+		bits = 0;
+	} else {
+		uint8_t uc;
+		uc = value->value.binary_vector.bits[lmfb];
+		bits = (lmfb+1) * 8;
+		/*
+		 * Squeeze the bit string width until the rightmost
+		 * bit is set.
+		 */
+		for(; uc && (uc & 1) == 0; uc >>= 1)
+			bits--;
+		if(uc == 0) {
+			bits = lmfb * 8;
+		}
+	}
+	value->value.binary_vector.size_in_bits = bits;
+}
+
+static int
+asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype) {
+	asn1p_t *asn;
+	asn1p_module_t *mod;
+	asn1p_expr_t *V;
+	asn1p_expr_t *bit;
+	asn1_integer_t aI;
+	uint8_t *bitbuf;
+	int bits;
+	int psize;
+	char *p;
+	int ret;
+	int r_value = 0;
+
+	assert(value->type == ATV_UNPARSED);
+
+	psize = value->value.string.size + 64;
+	p = malloc(psize);
+	if(p == NULL)
+		return -1;
+
+	ret = snprintf(p, psize,
+		"M DEFINITIONS ::=\nBEGIN\n"
+		"V ::= INTEGER %s\n"
+		"END\n",
+		value->value.string.buf
+	);
+	assert(ret < psize);
+	psize = ret;
+
+	asn = asn1p_parse_buffer(p, psize, A1P_NOFLAGS);
+	free(p);
+	if(asn == NULL) {
+		FATAL("Cannot parse BIT STRING value %s "
+			"defined as %s at line %d",
+			arg->expr->Identifier,
+			value->value.string.buf,
+			arg->expr->_lineno
+		);
+		return -1;
+	}
+
+	mod = TQ_FIRST(&(asn->modules));
+	assert(mod);
+	V = TQ_FIRST(&(mod->members));
+	assert(V);
+	assert(strcmp(V->Identifier, "V") == 0);
+	assert(TQ_FIRST(&(V->members)));
+
+	/*
+	 * Simple loop just to fetch the maximal bit position
+	 * out of the BIT STRING value defined as NamedBitList.
+	 */
+	aI = -1;
+	TQ_FOR(bit, &(V->members), next) {
+		asn1p_expr_t *bitdef;
+		bitdef = asn1f_lookup_child(ttype, bit->Identifier);
+		if(bitdef && bitdef->value
+		&& bitdef->value->type == ATV_INTEGER) {
+			if(bitdef->value->value.v_integer > aI)
+				aI = bitdef->value->value.v_integer;
+		}
+	}
+
+	if(aI > 1024 * 1024 * 8) {	/* One megabyte */
+		FATAL("Unsupportedly large BIT STRING value \"%s\" "
+			"defined at line %d "
+			"(larger than 1MByte)",
+			arg->expr->Identifier,
+			arg->expr->_lineno
+		);
+		asn1p_free(asn);
+		return -1;
+	}
+
+	bits = aI + 1;	/* Number of bits is more than a last bit position */
+	bitbuf = calloc(1, 1 + ((bits + 7) / 8));
+	if(bitbuf == NULL) {
+		asn1p_free(asn);
+		return -1;
+	}
+
+	TQ_FOR(bit, &(V->members), next) {
+		asn1p_expr_t *bitdef;
+		int set_bit_pos;
+
+		if(bit->value) {
+			WARNING("Identifier \"%s\" at line %d "
+				"must not have a value",
+				bit->Identifier, bit->_lineno);
+			RET2RVAL(1, r_value);
+		}
+		bitdef = asn1f_lookup_child(ttype, bit->Identifier);
+		if(bitdef == NULL) {
+			FATAL("Identifier \"%s\" at line %d is not defined "
+				"in the \"%s\" type definition at line %d",
+				bit->Identifier,
+				bit->_lineno,
+				ttype->Identifier,
+				ttype->_lineno
+			);
+			RET2RVAL(-1, r_value);
+			continue;
+		}
+		if(bitdef->value == NULL
+		|| bitdef->value->type != ATV_INTEGER) {
+			FATAL("Broken identifier "
+				"\"%s\" at line %d "
+				"referenced by \"%s\" at line %d",
+				bitdef->Identifier,
+				bitdef->_lineno,
+				arg->expr->Identifier,
+				arg->expr->_lineno
+			);
+			RET2RVAL(-1, r_value);
+			continue;
+		}
+
+		assert(bitdef->value->value.v_integer < bits);
+		set_bit_pos = bitdef->value->value.v_integer;
+		bitbuf[set_bit_pos>>3] |= 1 << (7-(set_bit_pos % 8));
+	}
+
+	asn1p_free(asn);
+	free(value->value.string.buf);
+	value->type = ATV_BITVECTOR;
+	value->value.binary_vector.bits = bitbuf;
+	value->value.binary_vector.size_in_bits = bits;
+
+	return r_value;
+}
diff --git a/libasn1fix/asn1fix_bitstring.h b/libasn1fix/asn1fix_bitstring.h
new file mode 100644
index 0000000..1230856
--- /dev/null
+++ b/libasn1fix/asn1fix_bitstring.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_BIT_STRING_H_
+#define	_ASN1FIX_BIT_STRING_H_
+
+int asn1f_fix_bit_string(arg_t *);
+
+#endif	/* _ASN1FIX_BIT_STRING_H_ */
diff --git a/libasn1fix/asn1fix_class.c b/libasn1fix/asn1fix_class.c
new file mode 100644
index 0000000..c541fd6
--- /dev/null
+++ b/libasn1fix/asn1fix_class.c
@@ -0,0 +1,237 @@
+#include "asn1fix_internal.h"
+
+typedef enum field_category {
+	OFC_INVALID,		/* Invalid object field category */
+	OFC_TYPE,
+	OFC_FIXED_TYPE_VALUE,
+	OFC_VARIABLE_TYPE_VALUE,
+	OFC_FIXED_TYPE_VALUE_SET,
+	OFC_VARIABLE_TYPE_VALUE_SET,
+	OFC_INFORMATION_OBJECT,
+	OFC_INFORMATION_OBJECT_SET,
+} field_category_e;
+
+typedef enum object_category {
+	OC_INVALID,
+	OC_OBJECT,
+	OC_OBJECTSET,
+} object_category_e;
+
+static field_category_e  asn1f_class_field_category(asn1p_expr_t *ofield);
+static object_category_e asn1f_class_object_category(asn1p_expr_t *expr);
+static asn1p_expr_t *
+asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref);
+
+asn1p_expr_t *
+asn1f_class_access(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **mod_r) {
+	asn1p_expr_t *obj;		/* Information Object or Object Set */
+	object_category_e obj_cat;	/* Object category */
+	//field_category_e field_cat;	/* Field category */
+	asn1p_expr_t *result;
+	asn1p_ref_t tmpref;
+
+	assert(ref->comp_count > 1);
+
+	DEBUG("%s(%s) for line %d", __func__,
+		asn1f_printable_reference(ref),
+		ref->_lineno);
+
+	/*
+	 * Fetch the first part of the reference (OBJECT or ObjectSet).
+	 * OBJECT.&<something>...
+	 * ObjectSet.&<something>...
+	 */
+	assert(isupper(ref->components[0].name[0]));
+
+	tmpref = *ref;
+	tmpref.comp_count = 1;
+	obj = asn1f_lookup_symbol(arg, &tmpref, 0);
+	if(obj == NULL) {
+		errno = ESRCH;
+		return NULL;
+	}
+
+	/*
+	 * Make sure the symbol lexical property (upper-case, lower-case)
+	 * corresponds to the type of the expression returned by
+	 * lookup_symbol().
+	 */
+	obj_cat = asn1f_class_object_category(obj);
+	switch(obj_cat) {
+	case OC_OBJECT:
+	case OC_OBJECTSET:
+		if(ref->components[0].lex_type
+			== (obj_cat==OC_OBJECT)
+				? RLT_CAPITALS
+				: RLT_Uppercase)
+			break;
+		/* Fall through */
+	case OC_INVALID:
+		WARNING("Symbol \"%s\" is not compatible "
+			"with referenced expression \"%s\" at line %d",
+			ref->components[0].name,
+			obj->Identifier, obj->_lineno);
+		errno = EPERM;
+		return NULL;
+	}
+
+	/*
+	 * Find the specified field within the object.
+	 */
+	result = asn1f_class_dot_lookup(arg, obj, ref);
+	if(result == NULL) {
+		return NULL;
+	}
+
+	//field_cat = asn1f_class_field_category(result);
+
+	DEBUG("FILLME: %s", result->Identifier);
+
+	return result;
+}
+
+static object_category_e
+asn1f_class_object_category(asn1p_expr_t *expr) {
+
+	switch(expr->meta_type) {
+	case AMT_OBJECT:
+		return OC_OBJECT;
+	case AMT_OBJECTSET:
+		return OC_OBJECTSET;
+	case AMT_VALUESET:
+		if(expr->expr_type == A1TC_REFERENCE
+		&& expr->reference
+		&& expr->reference->comp_count == 1
+		&& expr->reference->components[0].lex_type == RLT_CAPITALS)
+		{
+			/* FIXME: use find_terminal_type instead! */
+			return OC_OBJECTSET;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return OC_INVALID;
+}
+
+static field_category_e
+asn1f_class_field_category(asn1p_expr_t *ofield) {
+	if(ofield->Identifier[0] != '&') {
+		assert(ofield->Identifier[0] == '&');
+		return OFC_INVALID;
+	}
+
+	if(isupper(ofield->Identifier[1])) {
+		if(ofield->reference) {
+			enum asn1p_ref_lex_type_e lex_type
+				= ofield->reference->components[0].lex_type;
+
+			switch(lex_type) {
+			case RLT_CAPITALS:
+				return OFC_INFORMATION_OBJECT_SET;
+			case RLT_Uppercase:
+				return OFC_FIXED_TYPE_VALUE_SET;
+			case RLT_AmpUppercase:
+				return OFC_VARIABLE_TYPE_VALUE_SET;
+			default:
+				break;
+			}
+		} else {
+			if(ofield->expr_type == A1TC_CLASSFIELD)
+				return OFC_TYPE;
+
+			switch(ofield->meta_type) {
+			case AMT_TYPE:
+			case AMT_TYPEREF:
+				return OFC_FIXED_TYPE_VALUE_SET;
+			default:
+				break;
+			}
+
+		}
+	} else {
+		if(ofield->reference) {
+			enum asn1p_ref_lex_type_e lex_type
+				= ofield->reference->components[0].lex_type;
+
+			switch(lex_type) {
+			case RLT_CAPITALS:
+				return OFC_INFORMATION_OBJECT;
+			case RLT_Uppercase:
+				return OFC_FIXED_TYPE_VALUE;
+			case RLT_AmpUppercase:
+				return OFC_VARIABLE_TYPE_VALUE;
+			default:
+				break;
+			}
+		} else {
+			switch(ofield->meta_type) {
+			case AMT_TYPE:
+			case AMT_TYPEREF:
+				return OFC_FIXED_TYPE_VALUE;
+			default:
+				break;
+			}
+		}
+	}
+
+	return OFC_INVALID;
+}
+
+
+static asn1p_expr_t *
+asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref) {
+	asn1p_expr_t *ofield = NULL;	/* Information Object's Field */
+	field_category_e field_cat;	/* Field category */
+	int comp;
+
+	assert(ref->comp_count >= 2);
+
+	for(comp = 1 /* sic! */; comp < ref->comp_count; comp++) {
+		int is_last_component = (comp + 1 == ref->comp_count);
+		char *comp_name = ref->components[comp].name;
+
+		ofield = asn1f_lookup_child(obj, comp_name);
+		if(ofield == NULL) {
+			DEBUG("Cannot find field \"%s\" in \"%s\" at line %d",
+				ref->components[1].name,
+				obj->Identifier,
+				obj->_lineno);
+		}
+
+		/*
+		 * Compute the category of the field of
+		 * the information object class.
+		 */
+		field_cat = asn1f_class_field_category(ofield);
+
+		switch(field_cat) {
+		case OFC_INVALID:
+			WARNING("Invalid field category of \"%s\" at line %d",
+				ofield->Identifier, ofield->_lineno);
+			errno = EPERM;
+			return NULL;
+		case OFC_TYPE:
+		case OFC_FIXED_TYPE_VALUE:
+		case OFC_VARIABLE_TYPE_VALUE:
+		case OFC_FIXED_TYPE_VALUE_SET:
+		case OFC_VARIABLE_TYPE_VALUE_SET:
+			if(!is_last_component) {
+				FATAL("Field name component \"%s\" at line %d "
+					"specifies non-dereferenceable thing",
+					comp_name, ref->_lineno);
+				errno = EPERM;
+				return NULL;
+			}
+			break;
+		case OFC_INFORMATION_OBJECT:
+		case OFC_INFORMATION_OBJECT_SET:
+			obj = ofield;
+			break;
+		}
+	}
+
+	assert(ofield);
+	return ofield;
+}
diff --git a/libasn1fix/asn1fix_class.h b/libasn1fix/asn1fix_class.h
new file mode 100644
index 0000000..c849b2b
--- /dev/null
+++ b/libasn1fix/asn1fix_class.h
@@ -0,0 +1,16 @@
+#ifndef	_ASN1FIX_CLASS_H_
+#define	_ASN1FIX_CLASS_H_
+
+/*
+ * Fetch the element from the class-related stuff (thing) by its reference.
+ */
+asn1p_expr_t *
+asn1f_class_access(arg_t *, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+/*
+ * Externally accessible version of above function.
+ */
+asn1p_expr_t *asn1f_class_access2(asn1p_t *asn, asn1p_module_t *mod,
+	asn1p_expr_t *expr, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+#endif	/* _ASN1FIX_CLASS_H_ */
diff --git a/libasn1fix/asn1fix_compat.c b/libasn1fix/asn1fix_compat.c
new file mode 100644
index 0000000..aef26c0
--- /dev/null
+++ b/libasn1fix/asn1fix_compat.c
@@ -0,0 +1,132 @@
+#include "asn1fix_internal.h"
+
+static int asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
+
+/*
+ * Check that the expressions given are compatible in their type.
+ * ORDER DOES MATTER! (See .h).
+ */
+int
+asn1f_check_type_compatibility(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+	asn1p_expr_type_e atype, btype;
+
+	atype = a->expr_type;
+	btype = b->expr_type;
+
+	DEBUG("%s(%s:%x@%d, %s:%x@%d)", __func__,
+		a->Identifier, atype, a->_lineno,
+		b->Identifier, btype, b->_lineno);
+
+	/*
+	 * Expected terminal type!
+	 */
+	assert(atype != A1TC_REFERENCE);
+	assert(btype != A1TC_REFERENCE);
+
+	if(atype != btype) {
+		/*
+		 * Limited compatibility.
+		 */
+		if((atype == A1TC_UNIVERVAL && btype == ASN_BASIC_INTEGER)
+		|| (atype == A1TC_UNIVERVAL && btype == ASN_BASIC_ENUMERATED)
+		)
+			return 0;
+		DEBUG("\t%s and %s are not compatible",
+			a->Identifier, b->Identifier);
+		return -1;	/* Fairly obviously */
+	}
+
+	if(a == b)
+		return 0;	/* Fairly obviously */
+
+	switch(atype) {
+	case ASN_BASIC_INTEGER:
+		/* All integers are compatible */
+		return 0;
+	case ASN_BASIC_ENUMERATED:
+		/*
+		 * Enumerations are not compatible
+		 * unless their definitions are the same.
+		 */
+		if(asn1f_check_same_children(arg, a, b)) {
+			DEBUG("\tEnumerations are different %s and %s",
+				a->Identifier, b->Identifier);
+			return -1;
+		}
+		return 0;
+	default:
+		/* Compatibility is not defined yet */
+		DEBUG("\tCompatibility rule is not defined for %s and %s",
+			a->Identifier, b->Identifier);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Check that the children are exactly same.
+ */
+static int
+asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+	asn1p_expr_t *achild;
+	asn1p_expr_t *bchild;
+
+	achild = TQ_FIRST(&(a->members));
+	bchild = TQ_FIRST(&(b->members));
+
+	while(1) {
+		if(achild->expr_type != bchild->expr_type)
+			return -1;
+
+		if(achild->Identifier && bchild->Identifier) {
+			if(strcmp(achild->Identifier, bchild->Identifier))
+				return -1;
+		} else if(!(!achild->Identifier && !bchild->Identifier)) {
+			return -1;
+		}
+
+		if(achild->value && bchild->value) {
+			if(achild->value->type != bchild->value->type)
+				return -1;
+			switch(achild->value->type) {
+			case ATV_INTEGER:
+				if(achild->value->value.v_integer
+				!= bchild->value->value.v_integer)
+					return -1;
+				break;
+			case ATV_REFERENCED:
+			default:
+				DEBUG("Value %s at lines %d and "
+					"%d cannot be used in "
+					"semantical equality check",
+					asn1f_printable_value(achild->value),
+					achild->value->value.reference->_lineno,
+					bchild->value->value.reference->_lineno
+				);
+				return -1;
+			}
+		} else if(!(!achild->value && !bchild->value)) {
+			/* One of values is defined, and another is not */
+			return -1;
+		}
+
+		achild = TQ_NEXT(achild, next);
+		bchild = TQ_NEXT(bchild, next);
+
+		if(achild && bchild)
+			continue;
+		else if(!achild && !bchild)
+			break;
+		else
+			return -1;
+	}
+
+	DEBUG("\t%s:%x@%d and %s:%x@%d are semantically equivalent",
+		a->Identifier, a->expr_type, a->_lineno,
+		b->Identifier, b->expr_type, b->_lineno);
+
+	return 0;
+}
+
+
diff --git a/libasn1fix/asn1fix_compat.h b/libasn1fix/asn1fix_compat.h
new file mode 100644
index 0000000..429e7dd
--- /dev/null
+++ b/libasn1fix/asn1fix_compat.h
@@ -0,0 +1,14 @@
+#ifndef	_ASN1FIX_COMPAT_H_
+#define	_ASN1FIX_COMPAT_H_
+
+/*
+ * Check that the expressions given are compatible in their type.
+ * ORDER DOES MATTER!
+ * The compatibility is being checked as if the value of b were used
+ * to assign it to type a.
+ */
+int asn1f_check_type_compatibility(arg_t *arg,
+	asn1p_expr_t *a,
+	asn1p_expr_t *b);
+
+#endif	/* _ASN1FIX_COMPAT_H_ */
diff --git a/libasn1fix/asn1fix_constr.c b/libasn1fix/asn1fix_constr.c
new file mode 100644
index 0000000..2aa7982
--- /dev/null
+++ b/libasn1fix/asn1fix_constr.c
@@ -0,0 +1,364 @@
+#include "asn1fix_internal.h"
+
+static int _asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v);
+static int _asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
+
+
+int
+asn1f_fix_constr_ext(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *v;
+	TQ_HEAD(asn1p_expr_t) root_list;
+	TQ_HEAD(asn1p_expr_t) ext_list;
+	TQ_HEAD(asn1p_expr_t) *cur_list;
+	int r_value = 0;
+	int ext_count = 0;
+
+	switch(expr->expr_type) {
+	case ASN_CONSTR_SEQUENCE:
+	case ASN_CONSTR_SET:
+	case ASN_CONSTR_CHOICE:
+		break;
+	default:
+		return 0;
+	}
+
+	DEBUG("%s(%s) for line %d", __func__,
+		expr->Identifier, expr->_lineno);
+
+	TQ_INIT(&root_list);
+	TQ_INIT(&ext_list);
+	cur_list = (void *)&root_list;
+
+	while((v = TQ_REMOVE(&(expr->members), next))) {
+		if(v->expr_type == A1TC_EXTENSIBLE) {
+			ext_count++;
+			switch(ext_count) {
+			case 1: cur_list = (void *)&ext_list; break;
+			case 2:
+				cur_list = (void *)&root_list;
+				if(v->value) {
+					FATAL("Optional extension marker "
+						"must not contain "
+						"an exception mark "
+						"at line %d", v->_lineno);
+					r_value = -1;
+				}
+				asn1p_expr_free(v);
+				continue;
+			case 3:
+				FATAL("Third extension marker "
+				"is not allowed at line %d", v->_lineno);
+			default:
+				r_value = -1;
+			}
+		}
+
+		TQ_ADD(cur_list, v, next);
+	}
+
+	/*
+	 * Copy the root list and extension list back into the main list.
+	 */
+	TQ_HEAD_COPY(&(expr->members), &root_list);
+	while((v = TQ_REMOVE(&ext_list, next)))
+		TQ_ADD(&(expr->members), v, next);
+
+	if(arg->mod->module_flags & MSF_EXTENSIBILITY_IMPLIED
+	&& ext_count < 1) {
+		v = asn1p_expr_new(0);
+		if(v) {
+			v->Identifier = strdup("...");
+			v->expr_type = A1TC_EXTENSIBLE;
+			v->meta_type = AMT_TYPE;
+			if(v->Identifier == NULL) {
+				asn1p_expr_free(v);
+				r_value = -1;
+			} else {
+				TQ_ADD(&(expr->members), v, next);
+			}
+		} else {
+			r_value = -1;
+		}
+	}
+
+	return r_value;
+}
+
+
+int
+asn1f_fix_constr_tag(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *v;
+	int fl_impl_tags = 0;
+	int fl_auto_tags = 0;
+	int root_tagged = 0;	/* The root component is manually tagged */
+	int ext_tagged = 0;	/* The extensions are manually tagged */
+	int component_number = 0;
+	int r_value = 0;
+
+	switch(expr->expr_type) {
+	case ASN_CONSTR_SEQUENCE:
+	case ASN_CONSTR_SET:
+	case ASN_CONSTR_CHOICE:
+		break;
+	default:
+		return 0;
+	}
+
+	fl_impl_tags = (arg->mod->module_flags & MSF_IMPLICIT_TAGS);
+	fl_auto_tags = (arg->mod->module_flags & MSF_AUTOMATIC_TAGS);
+
+	DEBUG("%s(%s) {%d, %d} for line %d", __func__,
+		expr->Identifier, fl_impl_tags, fl_auto_tags, expr->_lineno);
+
+	TQ_FOR(v, &(expr->members), next) {
+		int must_explicit = 0;
+
+		if(v->expr_type == A1TC_EXTENSIBLE) {
+			component_number++;
+			continue;
+		}
+
+		if(v->tag.tag_class == TC_NOCLASS) {
+			continue;
+		} else {
+			switch(component_number) {
+			case 0: case 2:
+				root_tagged = 1; break;
+			default:
+				ext_tagged = 1; break;
+			}
+		}
+
+		must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
+
+		if(fl_impl_tags) {
+			if(v->tag.tag_mode != TM_EXPLICIT) {
+				if(must_explicit)
+					v->tag.tag_mode = TM_EXPLICIT;
+				else
+					v->tag.tag_mode = TM_IMPLICIT;
+			}
+		} else {
+			if(v->tag.tag_mode == TM_DEFAULT) {
+				v->tag.tag_mode = TM_EXPLICIT;
+			}
+		}
+
+		/*
+		 * Perform a final sanity check.
+		 */
+		if(must_explicit) {
+			if(v->tag.tag_mode == TM_IMPLICIT) {
+				FATAL("%s tagged in IMPLICIT mode "
+					"but must be EXPLICIT at line %d",
+					v->Identifier, v->_lineno);
+				r_value = -1;
+			} else {
+				v->tag.tag_mode = TM_EXPLICIT;
+			}
+		}
+	}
+
+	if(ext_tagged && !root_tagged) {
+		FATAL("In %s at line %d: "
+			"extensions are tagged "
+			"but root components are not",
+			expr->Identifier, expr->_lineno);
+		r_value = -1;
+	} else if(!root_tagged && !ext_tagged && fl_auto_tags) {
+		expr->auto_tags_OK = 1;
+	}
+
+	return r_value;
+}
+
+int
+asn1f_fix_constr_autotag(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *v;
+	asn1_integer_t tag_value = 0;
+	int r_value = 0;
+
+	switch(expr->expr_type) {
+	case ASN_CONSTR_SEQUENCE:
+	case ASN_CONSTR_SET:
+	case ASN_CONSTR_CHOICE:
+		if(expr->auto_tags_OK)
+			break;
+		/* Automatic tagging is not applicable */
+		/* Fall through */
+	default:
+		return 0;
+	}
+
+	DEBUG("%s(%s) for line %d", __func__,
+		expr->Identifier, expr->_lineno);
+
+	TQ_FOR(v, &(expr->members), next) {
+		int must_explicit;
+
+		if(v->expr_type == A1TC_EXTENSIBLE)
+			break;
+
+		assert(v->tag.tag_class == TC_NOCLASS);
+
+		must_explicit = _asn1f_check_if_tag_must_be_explicit(arg, v);
+
+		v->tag.tag_class = TC_CONTEXT_SPECIFIC;
+		v->tag.tag_mode = must_explicit ? TM_EXPLICIT : TM_IMPLICIT;
+		v->tag.tag_value = tag_value++;
+	}
+
+	return r_value;
+}
+
+/*
+ * Check that tags are distinct.
+ */
+int
+asn1f_check_constr_tags_distinct(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *v;
+	int r_value = 0;
+
+	switch(expr->expr_type) {
+	case ASN_CONSTR_SEQUENCE:
+	case ASN_CONSTR_SET:
+	case ASN_CONSTR_CHOICE:
+		break;
+	default:
+		return 0;
+	}
+
+	TQ_FOR(v, &(expr->members), next) {
+		/*
+		 * In every series of non-mandatory components,
+		 * the tags must be distinct from each other AND the
+		 * tag of the following mandatory component.
+		 * For SET and CHOICE treat everything as a big set of
+		 * non-mandatory components.
+		 */
+		if(expr->expr_type != ASN_CONSTR_SEQUENCE || v->marker) {
+			asn1p_expr_t *nv;
+			for(nv = v; (nv = TQ_NEXT(nv, next));) {
+				if(_asn1f_compare_tags(arg, v, nv))
+					r_value = -1;
+				if(expr->expr_type == ASN_CONSTR_SEQUENCE
+				&& !nv->marker) break;
+			}
+		}
+	}
+
+	return r_value;
+}
+
+static int
+_asn1f_check_if_tag_must_be_explicit(arg_t *arg, asn1p_expr_t *v) {
+	asn1p_expr_t *reft;
+
+	reft = asn1f_find_terminal_type(arg, v, 0);
+	if(reft) {
+		switch(reft->expr_type) {
+		case ASN_CONSTR_CHOICE:
+			return 1;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Check that the tags are distinct.
+ */
+static int
+_asn1f_compare_tags(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
+	struct asn1p_type_tag_s ta, tb;
+	int ra, rb;
+	int ret;
+
+	ra = asn1f_fetch_tag(arg->asn, arg->mod, a, &ta);
+	rb = asn1f_fetch_tag(arg->asn, arg->mod, b, &tb);
+
+	/*
+	 * If both tags are explicitly or implicitly given, use them.
+	 */
+	if(ra == 0 && rb == 0) {
+		/*
+		 * Simple case: fetched both tags.
+		 */
+		if(ta.tag_value == tb.tag_value
+		&& ta.tag_class == tb.tag_class) {
+			char *p = (a->expr_type == A1TC_EXTENSIBLE)
+				?"potentially ":"";
+			FATAL("Component \"%s\" at line %d %shas the same tag "
+				"with component \"%s\" at line %d",
+				a->Identifier,
+				a->_lineno,
+				p,
+				b->Identifier,
+				b->_lineno
+			);
+			return -1;
+		} else {
+			/* Tags are distinct */
+			return 0;
+		}
+	}
+
+	/**********************************************************
+	 * Now we must perform some very funny recursion to check
+	 * multiple components of CHOICE type, etc.
+	 */
+
+	DEBUG("Comparing tags %s:%x <-> %s:%x",
+		a->Identifier, a->expr_type,
+		b->Identifier, b->expr_type);
+
+	if(a->meta_type == AMT_TYPEREF) {
+		asn1p_module_t *mod;
+
+		DEBUG(" %s is a type reference", a->Identifier);
+
+		a = asn1f_lookup_symbol(arg, a->reference, &mod);
+		if(!a) return 0;	/* Already FATAL()'ed somewhere else */
+		WITH_MODULE(mod, ret = _asn1f_compare_tags(arg, a, b));
+		return ret;
+	}
+
+	if(a->expr_type == ASN_CONSTR_CHOICE) {
+		asn1p_expr_t *v;
+
+		DEBUG(" %s is a choice type (%d)", a->Identifier, a->_mark);
+
+		/*
+		 * Iterate over members of CHOICE.
+		 */
+		//if(a->_mark & TM_RECURSION) return 0;
+		TQ_FOR(v, &(a->members), next) {
+			//a->_mark |= TM_RECURSION;
+			ret = _asn1f_compare_tags(arg, v, b);
+			//a->_mark &= ~TM_RECURSION;
+			if(ret) return ret;
+		}
+		return 0;
+	}
+
+	if(b->expr_type == ASN_CONSTR_CHOICE) {
+		return _asn1f_compare_tags(arg, b, a);
+	}
+
+	if(a->_mark & TM_RECURSION) return 0;
+	if(b->_mark & TM_RECURSION) return 0;
+	a->_mark |= TM_RECURSION;
+	b->_mark |= TM_RECURSION;
+	ret = _asn1f_compare_tags(arg, b, a);
+	a->_mark &= ~TM_RECURSION;
+	b->_mark &= ~TM_RECURSION;
+
+	return ret;
+}
+
diff --git a/libasn1fix/asn1fix_constr.h b/libasn1fix/asn1fix_constr.h
new file mode 100644
index 0000000..aeb05c0
--- /dev/null
+++ b/libasn1fix/asn1fix_constr.h
@@ -0,0 +1,24 @@
+#ifndef	_ASN1FIX_CONSTRUCTED_H_
+#define	_ASN1FIX_CONSTRUCTED_H_
+
+/*
+ * Fix extensions in constructed types.
+ */
+int asn1f_fix_constr_ext(arg_t *);
+
+/*
+ * Fix tagging in constructed types.
+ */
+int asn1f_fix_constr_tag(arg_t *);
+
+/*
+ * Check distinctive tagging in constructed types.
+ */
+int asn1f_check_constr_tags_distinct(arg_t *);
+
+/*
+ * Perform automatic tagging.
+ */
+int asn1f_fix_constr_autotag(arg_t *);
+
+#endif	/* _ASN1FIX_CONSTRUCTED_H_ */
diff --git a/libasn1fix/asn1fix_cstring.c b/libasn1fix/asn1fix_cstring.c
new file mode 100644
index 0000000..b8a3883
--- /dev/null
+++ b/libasn1fix/asn1fix_cstring.c
@@ -0,0 +1,73 @@
+#include "asn1fix_internal.h"
+
+struct _cstring_pattern {
+	char *start;
+	int length;
+};
+static int _asn1f_cstring_find_line_pattern(char *s, struct _cstring_pattern *);
+
+int
+asn1f_fix_cstring(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	int r_value = 0;
+
+	if(expr->value && expr->value->type == ATV_STRING) {
+		struct _cstring_pattern cp;
+		char *buf = expr->value->value.string.buf;
+		int buflen = expr->value->value.string.size;
+		int start = 0;
+
+		DEBUG("%s(%s) for line %d", __func__,
+			expr->Identifier, expr->_lineno);
+
+		while(_asn1f_cstring_find_line_pattern(buf + start, &cp)) {
+			assert(cp.length);
+			memmove(cp.start, cp.start + cp.length,
+				buflen - ((cp.start + cp.length) - buf));
+			buflen -= cp.length;
+			start = cp.start - buf;
+			buf[buflen] = '\0';
+		}
+	}
+
+	return r_value;
+}
+
+/*
+ * If a string has a newline, the tabulation and spaces before and
+ * after it must be eliminated.
+ */
+static int
+_asn1f_cstring_find_line_pattern(char *s, struct _cstring_pattern *cp) {
+	int newline_found = 0;
+
+	cp->start = NULL;
+
+	for(;;s++) {
+		switch(*s) {
+		case '\r': case '\n':
+			newline_found = 1;
+			/* Fall through */
+		case ' ': case '\t':
+			if(cp->start == NULL)
+				cp->start = s;
+			continue;
+		case '\0':
+		default:
+			if(newline_found) {
+				cp->length = s - cp->start;
+				return 1;
+			}
+
+			cp->start = NULL;
+			if(*s == '\0')
+				break;
+			continue;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+
diff --git a/libasn1fix/asn1fix_cstring.h b/libasn1fix/asn1fix_cstring.h
new file mode 100644
index 0000000..bd647ab
--- /dev/null
+++ b/libasn1fix/asn1fix_cstring.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_CSTRING_H_
+#define	_ASN1FIX_CSTRING_H_
+
+int asn1f_fix_cstring(arg_t *);
+
+#endif	/* _ASN1FIX_CSTRING_H_ */
diff --git a/libasn1fix/asn1fix_dereft.c b/libasn1fix/asn1fix_dereft.c
new file mode 100644
index 0000000..f0ec9a6
--- /dev/null
+++ b/libasn1fix/asn1fix_dereft.c
@@ -0,0 +1,68 @@
+#include "asn1fix_internal.h"
+
+int
+asn1f_fix_dereference_types(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *type_expr;
+	int r_value = 0;
+
+	if(expr->expr_type == A1TC_PARAMETRIZED)
+		return asn1f_fix_parametrized_assignment(arg);
+
+	if(expr->expr_type != A1TC_REFERENCE
+	|| expr->meta_type != AMT_TYPEREF) {
+		//assert(expr->reference == 0);
+		return 0;	/* Just ignore it */
+	}
+
+	DEBUG("%s(\"%s\":%x ::= \"%s\") for line %d",
+		__func__, expr->Identifier, expr->expr_type,
+		asn1f_printable_value(expr->value),
+		expr->_lineno);
+
+	assert(TQ_FIRST(&(expr->members)) == 0);
+	assert(expr->reference);
+
+	/*
+	 * Follow the reference.
+	 */
+	type_expr = asn1f_find_terminal_type(arg, expr, 0);
+	if(type_expr == NULL) {
+		FATAL("Unknown type \"%s\" referenced by \"%s\" at line %d",
+			asn1f_printable_reference(expr->reference),
+			expr->Identifier, expr->_lineno);
+		return -1;
+	}
+
+	/*
+	 * Copying members of the source expression
+	 * into the current expression.
+	 */
+	if(0) {
+		asn1p_expr_t *tmp_clone;
+
+		tmp_clone = asn1p_expr_clone(type_expr);
+		if(tmp_clone == NULL) {
+			FATAL("Could not clone \"%s\" at line %d",
+				type_expr->Identifier, type_expr->_lineno);
+			return -1;
+		}
+
+		/*
+		 * Replace the referenced type with its definition.
+		 */
+		DEBUG("\tChanging type of \"%s\":%x to %x for line %d",
+			expr->Identifier,
+			expr->expr_type,
+			type_expr->expr_type,
+			expr->_lineno
+		);
+		expr->expr_type = type_expr->expr_type;
+		expr->members = tmp_clone->members;
+		memset(&tmp_clone->members, 0, sizeof(tmp_clone->members));
+		asn1p_expr_free(tmp_clone);
+	}
+
+	return r_value;
+}
+
diff --git a/libasn1fix/asn1fix_dereft.h b/libasn1fix/asn1fix_dereft.h
new file mode 100644
index 0000000..bee8151
--- /dev/null
+++ b/libasn1fix/asn1fix_dereft.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_DEREFT_H_
+#define	_ASN1FIX_DEREFT_H_
+
+int asn1f_fix_dereference_types(arg_t *);
+
+#endif	/* _ASN1FIX_DEREFT_H_ */
diff --git a/libasn1fix/asn1fix_derefv.c b/libasn1fix/asn1fix_derefv.c
new file mode 100644
index 0000000..7be9d6d
--- /dev/null
+++ b/libasn1fix/asn1fix_derefv.c
@@ -0,0 +1,56 @@
+#include "asn1fix_internal.h"
+
+/*
+ * Dereference DefinedValues:
+ */
+int
+asn1f_fix_dereference_values(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	int r_value = 0;
+
+	if(expr->meta_type != AMT_VALUE)
+		return 0;	/* Just ignore it */
+
+	if(expr->value == NULL)
+		return 0;	/* Just ignore it */
+
+	if(expr->value && expr->value->type != ATV_REFERENCED)
+		return 0;	/* Not a reference */
+
+	DEBUG("%s(%s %x ::= %s) for line %d", __func__,
+		expr->Identifier, expr->expr_type,
+		asn1f_printable_value(expr->value), expr->_lineno);
+
+	/*
+	 * If this integer has a value, check that this value
+	 * is an integer. If it is a reference, resolve it.
+	 */
+	if(expr->value) {
+
+		if(asn1f_value_resolve(arg, expr)) {
+			/* This function will emit messages */
+			r_value = -1;
+		}
+
+		if(expr->value->type != ATV_INTEGER) {
+			FATAL(
+				"INTEGER value %s at line %d: "
+				"Incompatible value specified: %s",
+				expr->Identifier,
+				expr->_lineno,
+				asn1f_printable_value(expr->value)
+			);
+			r_value = -1;
+		}
+	} else {
+		FATAL("Value of \"%s\" at line %d: "
+			"Incompatible value specified",
+			expr->Identifier,
+			expr->_lineno
+		);
+		r_value = -1;
+	}
+
+	return r_value;
+}
+
diff --git a/libasn1fix/asn1fix_derefv.h b/libasn1fix/asn1fix_derefv.h
new file mode 100644
index 0000000..9315385
--- /dev/null
+++ b/libasn1fix/asn1fix_derefv.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_DEREFV_H_
+#define	_ASN1FIX_DEREFV_H_
+
+int asn1f_fix_dereference_values(arg_t *);
+
+#endif	/* _ASN1FIX_DEREFV_H_ */
diff --git a/libasn1fix/asn1fix_enum.c b/libasn1fix/asn1fix_enum.c
new file mode 100644
index 0000000..8a90a43
--- /dev/null
+++ b/libasn1fix/asn1fix_enum.c
@@ -0,0 +1,136 @@
+#include "asn1fix_internal.h"
+
+/*
+ * Check the validity of an enumeration.
+ */
+int
+asn1f_fix_enum(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *ev;
+	asn1_integer_t max_value = -1;
+	int rvalue = 0;
+	asn1p_expr_t *ext_marker = NULL;	/* "..." position */
+	int ret;
+
+	if(expr->expr_type != ASN_BASIC_ENUMERATED)
+		return 0;	/* Just ignore it */
+
+	DEBUG("%s(%s)", __func__, expr->Identifier);
+
+	/*
+	 * 1. Scan the enumeration values in search for inconsistencies.
+	 */
+	TQ_FOR(ev, &(expr->members), next) {
+		asn1_integer_t eval;
+
+		if(ev->value)
+			DEBUG("\tItem %s(%s)", ev->Identifier,
+				asn1f_printable_value(ev->value));
+		else
+			DEBUG("\tItem %s", ev->Identifier);
+
+		/*
+		 * 1.1 Found an extension mark "...", check correctness.
+		 */
+		if(ev->expr_type == A1TC_EXTENSIBLE) {
+			if(ext_marker) {
+				arg->eh(1,
+				"Enumeration %s at line %d: "
+				"Second extension marker is not allowed",
+				expr->Identifier,
+				ev->_lineno);
+				rvalue = -1;
+			} else {
+				/*
+				 * Remember the marker's position.
+				 */
+				ext_marker = ev;
+			}
+			continue;
+		} else if(ev->Identifier == NULL
+			|| ev->expr_type != A1TC_UNIVERVAL) {
+			FATAL(
+				"Enumeration %s at line %d: "
+				"Unsupported enumeration element %s",
+				expr->Identifier,
+				ev->_lineno,
+				ev->Identifier?ev->Identifier:"<anonymous>");
+			rvalue = -1;
+			continue;
+		}
+
+		/*
+		 * 1.2 Compute the value of the enumeration element.
+		 */
+		if(ev->value) {
+			switch(ev->value->type) {
+			case ATV_INTEGER:
+				eval = ev->value->value.v_integer;
+				break;
+			case ATV_REFERENCED:
+				FATAL("HERE HERE HERE", 1);
+				rvalue = -1;
+				continue;
+				break;
+			default:
+				FATAL("ENUMERATED type %s at line %d "
+					"contain element %s(%s) at line %d",
+					expr->Identifier, expr->_lineno,
+					ev->Identifier,
+					asn1f_printable_value(ev->value),
+					ev->_lineno);
+				rvalue = -1;
+				continue;
+			}
+		} else {
+			eval = max_value + 1;
+			ev->value = asn1p_value_fromint(eval);
+			if(ev->value == NULL) {
+				rvalue = -1;
+				continue;
+			}
+		}
+
+		/*
+		 * 1.3 Check the applicability of this value.
+		 */
+		if(eval <= max_value) {
+			if(ext_marker) {
+				/*
+				 * Enumeration is allowed to be unordered
+				 * before the first marker.
+				 */
+				FATAL(
+					"Enumeration %s at line %d: "
+					"Explicit value \"%s(%lld)\" "
+					"is not greater "
+					"than previous values (max %lld)",
+					expr->Identifier,
+					ev->_lineno,
+					ev->Identifier,
+					eval,
+					max_value);
+				rvalue = -1;
+			}
+		} else if(eval > max_value) {
+			max_value = eval;
+		}
+
+		/*
+		 * 1.4 Check that all identifiers before the current one
+		 * differs from it.
+		 */
+		ret = asn1f_check_unique_expr_child(arg, ev, NULL);
+		RET2RVAL(ret, rvalue);
+	}
+
+
+	/*
+	 * 2. Reorder the first half (before optional "...") of the
+	 * identifiers alphabetically.
+	 */
+	// TODO
+
+	return rvalue;
+}
+
diff --git a/libasn1fix/asn1fix_enum.h b/libasn1fix/asn1fix_enum.h
new file mode 100644
index 0000000..14c6fb5
--- /dev/null
+++ b/libasn1fix/asn1fix_enum.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_ENUM_H_
+#define	_ASN1FIX_ENUM_H_
+
+int asn1f_fix_enum(arg_t *);	/* Enumeration ::= ENUMERATED { a(1), b(2) } */
+
+#endif	/* _ASN1FIX_ENUM_H_ */
diff --git a/libasn1fix/asn1fix_export.c b/libasn1fix/asn1fix_export.c
new file mode 100644
index 0000000..d6bb37b
--- /dev/null
+++ b/libasn1fix/asn1fix_export.c
@@ -0,0 +1,48 @@
+#include "asn1fix_internal.h"
+#include "asn1fix_export.h"
+
+asn1p_expr_t *
+asn1f_lookup_symbol_ex(
+		asn1p_t *asn,
+		asn1p_module_t **module_rw,
+		asn1p_expr_t *expr,
+		asn1p_ref_t *ref) {
+	arg_t arg;
+
+	memset(&arg, 0, sizeof(arg));
+
+	arg.asn = asn;
+	arg.mod = *module_rw;
+	arg.expr = expr;
+
+	return asn1f_lookup_symbol(&arg, ref, module_rw);
+}
+
+asn1p_expr_t *
+asn1f_class_access_ex(asn1p_t *asn,
+		asn1p_module_t *mod,
+		asn1p_expr_t *expr,
+		asn1p_ref_t *ref,
+		asn1p_module_t **mod_r) {
+	static arg_t arg;
+
+	arg.asn = asn;
+	arg.mod = mod;
+	arg.expr = expr;
+
+	return asn1f_class_access(&arg, ref, mod_r);
+}
+
+asn1p_expr_t *
+asn1f_find_terminal_type_ex(asn1p_t *asn,
+		asn1p_module_t *mod,
+		asn1p_expr_t *expr,
+		asn1p_module_t **mod_r) {
+	static arg_t arg;
+
+	arg.asn = asn;
+	arg.mod = mod;
+	arg.expr = expr;
+
+	return asn1f_find_terminal_type(&arg, expr, mod_r);
+}
diff --git a/libasn1fix/asn1fix_export.h b/libasn1fix/asn1fix_export.h
new file mode 100644
index 0000000..2ade0c9
--- /dev/null
+++ b/libasn1fix/asn1fix_export.h
@@ -0,0 +1,32 @@
+/*
+ * This header exports fixer procedures that are common enough to be used
+ * in other modules.
+ */
+#ifndef	_ASN1FIX_EXPORT_H_
+#define	_ASN1FIX_EXPORT_H_
+
+#include <asn1fix_tags.h>
+
+/*
+ *  Exportable version of an asn1f_lookup_symbol().
+ */
+asn1p_expr_t *asn1f_lookup_symbol_ex(
+		asn1p_t *asn,
+		asn1p_module_t **module_rw,
+		asn1p_expr_t *expr,
+		asn1p_ref_t *ref);
+
+/*
+ *  Exportable version of an asn1f_class_access().
+ */
+asn1p_expr_t *asn1f_class_access_ex(asn1p_t *asn, asn1p_module_t *mod,
+	asn1p_expr_t *expr, asn1p_ref_t *, asn1p_module_t **mod_r);
+
+/*
+ * Exportable version of asn1f_find_terminal_type().
+ */
+asn1p_expr_t *asn1f_find_terminal_type_ex(asn1p_t *asn, asn1p_module_t *mod,
+	asn1p_expr_t *tc, asn1p_module_t **opt_module_r);
+
+#endif	/* _ASN1FIX_EXPORT_H_ */
+
diff --git a/libasn1fix/asn1fix_integer.c b/libasn1fix/asn1fix_integer.c
new file mode 100644
index 0000000..514ab70
--- /dev/null
+++ b/libasn1fix/asn1fix_integer.c
@@ -0,0 +1,161 @@
+#include "asn1fix_internal.h"
+
+static int _compare_value(asn1p_expr_t *expr1, asn1p_expr_t *expr2) {
+	if(expr2->value->type == ATV_INTEGER
+	&& expr1->value->type == ATV_INTEGER) {
+		return expr2->value->value.v_integer
+			- expr1->value->value.v_integer;
+	} else {
+		return -1;
+	}
+}
+
+/*
+ * Check the validity of an INTEGER type.
+ */
+int
+asn1f_fix_integer(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *iv;
+	int rvalue = 0;
+	int ret;
+
+	if(expr->expr_type != ASN_BASIC_INTEGER)
+		return 0;	/* Just ignore it */
+
+	DEBUG("%s(\"%s\", %x) for line %d", __func__,
+		expr->Identifier, expr->expr_type, expr->_lineno);
+
+	/*
+	 * Scan the integer values in search for inconsistencies.
+	 */
+	TQ_FOR(iv, &(expr->members), next) {
+
+		DEBUG("\tItem %s(%s)", iv->Identifier,
+			asn1f_printable_value(iv->value));
+
+		/*
+		 * Found "...", check correctness.
+		 */
+		if(iv->expr_type == A1TC_EXTENSIBLE) {
+			arg->eh(1,
+				"INTEGER %s at line %d: "
+				"Extension marker is not allowed",
+				expr->Identifier,
+				iv->_lineno
+			);
+			rvalue = -1;
+			continue;
+		}
+
+		if(iv->Identifier == NULL
+		|| iv->expr_type != A1TC_UNIVERVAL) {
+			arg->eh(1,
+				"INTEGER %s at line %d: "
+				"Unsupported enumeration element %s",
+				expr->Identifier,
+				iv->_lineno,
+				iv->Identifier?iv->Identifier:"<Anonymous>"
+			);
+			rvalue = -1;
+			continue;
+		}
+
+		if(iv->value == NULL) {
+			arg->eh(1,
+				"INTEGER %s at line %d: "
+				"Value for the identifier %s "
+				"must be set explicitly",
+				expr->Identifier,
+				iv->_lineno,
+				iv->Identifier
+			);
+			rvalue = -1;
+			continue;
+		} else if(iv->value->type == ATV_REFERENCED) {
+			/*
+			 * Resolve the value, once and for all.
+			 */
+			if(asn1f_value_resolve(arg, iv)) {
+				/* This function will emit messages */
+				rvalue = -1;
+				continue;
+			}
+		}
+
+		if(iv->value->type != ATV_INTEGER) {
+			arg->eh(1,
+				"INTEGER %s at line %d: "
+				"Value for the identifier %s "
+				"is not compatible with INTEGER type",
+				expr->Identifier,
+				iv->_lineno);
+			rvalue = -1;
+			continue;
+		}
+
+		/*
+		 * Check that all identifiers are distinct.
+		 */
+		ret = asn1f_check_unique_expr_child(arg, iv, NULL);
+		RET2RVAL(ret, rvalue);
+		/*
+		 * Check that all values are distinct.
+		 */
+		ret = asn1f_check_unique_expr_child(arg, iv, _compare_value);
+		RET2RVAL(ret, rvalue);
+	}
+
+
+	return rvalue;
+}
+
+static int
+_asn1f_make_sure_type_is(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_type_e type) {
+	asn1p_module_t *mod = NULL;
+	asn1p_expr_t *next_expr;
+	int expr_type;
+	int ret;
+
+	expr_type = expr->expr_type;
+
+	/*
+	 * Here we're trying to make sure that the type of the given
+	 * expression is really what is expected.
+	 * This is ensured in two ways.
+	 * First, if the immediate type matches the provided one,
+	 * this is a clear hit.
+	 */
+	if(expr_type == type)
+		return 0;
+
+	/*
+	 * Otherwise, it must be either a reference or a different type.
+	 */
+	if(expr_type != A1TC_REFERENCE) {
+		errno = EPERM;
+		return -1;
+	}
+
+	assert(expr_type == A1TC_REFERENCE);
+	assert(expr->reference);
+
+	/*
+	 * Then, it is a reference. For a reference, try to resolve type
+	 * and try again.
+	 */
+	next_expr = asn1f_lookup_symbol(arg, expr->reference, &mod);
+	if(next_expr == NULL) {
+		errno = ESRCH;
+		return -1;
+	}
+
+	/*
+	 * If symbol is here, recursively check that it conforms to the type.
+	 */
+	WITH_MODULE(mod, ret = _asn1f_make_sure_type_is(arg, next_expr, type));
+
+	return ret;
+}
+
+
diff --git a/libasn1fix/asn1fix_integer.h b/libasn1fix/asn1fix_integer.h
new file mode 100644
index 0000000..d306fc0
--- /dev/null
+++ b/libasn1fix/asn1fix_integer.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_INTEGER_H_
+#define	_ASN1FIX_INTEGER_H_
+
+int asn1f_fix_integer(arg_t *);		/* Type1 ::= INTEGER { a(1), b(2) } */
+
+#endif	/* _ASN1FIX_INTEGER_H_ */
diff --git a/libasn1fix/asn1fix_internal.h b/libasn1fix/asn1fix_internal.h
new file mode 100644
index 0000000..ff3b4e9
--- /dev/null
+++ b/libasn1fix/asn1fix_internal.h
@@ -0,0 +1,106 @@
+#ifndef	_ASN1FIX_INTERNAL_H_
+#define	_ASN1FIX_INTERNAL_H_
+
+/*
+ * System headers required in various modules.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>		/* isupper() */
+#include <errno.h>
+#include <assert.h>
+
+#include <asn1parser.h>		/* Our lovely ASN.1 parser module */
+
+/*
+ * A definition of a function that will log error messages.
+ */
+typedef void (*error_logger_f)(int _is_fatal, const char *fmt, ...);
+
+/*
+ * Universal argument.
+ */
+typedef struct arg_s {
+	asn1p_t         *asn;
+	asn1p_module_t  *mod;
+	asn1p_expr_t    *expr;
+	error_logger_f   eh;
+	error_logger_f   debug;
+	void            *key;           /* The next level key */
+} arg_t;
+
+/*
+ * Functions performing normalization of various types.
+ */
+#include "asn1fix_misc.h"		/* Support functions */
+#include "asn1fix_value.h"		/* Value processing */
+#include "asn1fix_cstring.h"		/* Fix cstring values */
+#include "asn1fix_compat.h"		/* Data compatibility */
+#include "asn1fix_constr.h"		/* Constructed types */
+#include "asn1fix_class.h"		/* CLASS support */
+#include "asn1fix_param.h"		/* Parametrization */
+#include "asn1fix_retrieve.h"		/* Data retrieval */
+#include "asn1fix_enum.h"		/* Process ENUMERATED */
+#include "asn1fix_integer.h"		/* Process INTEGER */
+#include "asn1fix_bitstring.h"		/* Process BIT STRING */
+#include "asn1fix_dereft.h"		/* Dereference types */
+#include "asn1fix_derefv.h"		/* Dereference values */
+#include "asn1fix_tags.h"		/* Tags-related stuff */
+
+
+/*
+ * Merge the return value of the called function with the already
+ * partially computed return value of the current function.
+ */
+#define	RET2RVAL(ret,rv) do {					\
+		int __ret = ret;				\
+		switch(__ret) {					\
+		case  0: break;					\
+		case  1: if(rv) break;				\
+		case -1: rv = __ret; break;			\
+		default:					\
+			assert(__ret >= -1 && __ret <= 1);	\
+			rv = -1;				\
+		}						\
+	} while(0)
+
+/*
+ * Temporary substitute module for the purposes of evaluating expression.
+ */
+#define	WITH_MODULE(tmp_mod, expr)	do {			\
+		void *_saved_mod = arg->mod;			\
+		arg->mod = tmp_mod;				\
+		do { expr; } while(0);				\
+		arg->mod = _saved_mod;				\
+	} while(0)
+
+#define	LOG(code, fmt, args...) do {				\
+		int _save_errno = errno;			\
+		if(code < 0) {					\
+			if(arg->debug)				\
+				arg->debug(code, fmt, ##args);	\
+		} else {					\
+			arg->eh(code, fmt " in %s", ##args,	\
+				arg->mod->source_file_name);	\
+		}						\
+		errno = _save_errno;				\
+	} while(0)
+
+#define	DEBUG(fmt, args...)	LOG(-1, fmt, ##args)
+#define	FATAL(fmt, args...)	LOG( 1, fmt, ##args)
+#define	WARNING(fmt, args...)	LOG( 0, fmt, ##args)
+
+
+/*
+ * Define the symbol corresponding to the name of the current function.
+ */
+#if __STDC_VERSION__ < 199901
+#if !(__GNUC__ == 2 && __GNUC_MINOR__ >= 7 || __GNUC__ >= 3)
+#define __func__	(char *)0	/* Name of the current function */
+#endif	/* GNUC */
+/* __func__ is supposed to be defined */
+#endif
+
+
+#endif	/* _ASN1FIX_INTERNAL_H_ */
diff --git a/libasn1fix/asn1fix_misc.c b/libasn1fix/asn1fix_misc.c
new file mode 100644
index 0000000..5fe6903
--- /dev/null
+++ b/libasn1fix/asn1fix_misc.c
@@ -0,0 +1,276 @@
+#include "asn1fix_internal.h"
+
+
+char const *
+asn1f_printable_reference(asn1p_ref_t *ref) {
+	if(ref) {
+		asn1p_value_t v;
+
+		v.type = ATV_REFERENCED;
+		v.value.reference = ref;
+
+		return asn1f_printable_value(&v);
+	} else {
+		return "<no ref>";
+	}
+}
+
+char const *
+asn1f_printable_value(asn1p_value_t *v) {
+	static char buf[128];
+	static char *managedptr;
+	static int managedptr_len;
+	int ret;
+
+#define	ENSURE(len)	do {						\
+		if(len >= managedptr_len) {				\
+			if(managedptr)					\
+				free(managedptr);			\
+			managedptr = malloc(len + 1);			\
+			if(managedptr) {				\
+				managedptr_len = len;			\
+			} else {					\
+				managedptr_len = 0;			\
+				return "<memory allocation error>";	\
+			}						\
+		}							\
+	} while(0)
+
+	if(v == NULL)
+		return "<no value>";
+
+	switch(v->type) {
+	case ATV_NOVALUE:
+		return "<NO VALUE>";
+	case ATV_REFERENCED:
+		{
+			asn1p_ref_t *ref;
+			char reflen;
+			char *ptr;
+			int i;
+
+			assert(v->value.reference);
+			ref = v->value.reference;
+			reflen = ref->comp_count;	/* Number of dots */
+			for(i = 0; i < ref->comp_count; i++)
+				reflen += strlen(ref->components[i].name);
+			/*
+			 * Make sure we have a buffer of this size.
+			 */
+			ENSURE(reflen);
+
+			/*
+			 * Fill-up the buffer.
+			 */
+			ptr = managedptr;
+			for(i = 0; i < ref->comp_count; i++) {
+				char *nc;
+				if(i) *ptr++ = '.';
+				for(nc = ref->components[i].name; *nc; nc++)
+					*ptr++ = *nc;
+			}
+			*ptr++ = '\0';
+			assert(reflen == (ptr - managedptr));
+			return managedptr;
+		}
+	case ATV_REAL:
+		ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double);
+		if(ret >= sizeof(buf))
+			memcpy(buf + sizeof(buf) - 4, "...", 4);
+		return buf;
+	case ATV_INTEGER:
+		ret = snprintf(buf, sizeof(buf), "%lld",
+			(long long)v->value.v_integer);
+		if(ret >= sizeof(buf))
+			memcpy(buf + sizeof(buf) - 4, "...", 4);
+		return buf;
+	case ATV_MIN: return "MIN";
+	case ATV_MAX: return "MAX";
+	case ATV_FALSE: return "FALSE";
+	case ATV_TRUE: return "TRUE";
+	case ATV_STRING:
+	case ATV_UNPARSED:
+		/* Buffer is guaranteed to be null-terminated */
+		assert(v->value.string.buf[v->value.string.size] == '\0');
+		return v->value.string.buf;
+	case ATV_BITVECTOR:
+		{
+			uint8_t *bitvector;
+			char *ptr;
+			int len;
+			int i;
+			/*
+			 * Compute number of bytes necessary
+			 * to represend the binary value.
+			 */
+			int bits = v->value.binary_vector.size_in_bits;
+			len = ((bits%8)?bits:(bits >> 2)) + sizeof("''H");
+			/*
+			 * Reallocate managed buffer
+			 */
+			ENSURE(len);
+
+			/*
+			 * Fill the buffer.
+			 */
+			ptr = managedptr;
+			bitvector = v->value.binary_vector.bits;
+			*ptr++ = '\'';
+			if(bits%8) {
+				/*
+				 * Dump bit by bit.
+				 */
+				for(i = 0; i < bits; i++) {
+					uint8_t uc;
+					uc = bitvector[i>>3];
+					*ptr++ = ((uc >> (7-(i%8)))&1)?'1':'0';
+				}
+			} else {
+				char hextable[16] = "0123456789ABCDEF";
+				/*
+				 * Dump byte by byte.
+				 */
+				for(i = 0; i < (bits >> 3); i++) {
+					*ptr++ = hextable[bitvector[i] >> 4];
+					*ptr++ = hextable[bitvector[i] & 0x0f];
+				}
+			}
+			*ptr++ = '\'';
+			*ptr++ = (bits%8)?'B':'H';
+			*ptr++ = 'H';
+			assert((ptr - managedptr) == len);
+			return managedptr;
+		}
+	}
+
+	return "<some complex value>";
+}
+
+
+/*
+ * Recursively invoke a given function over the given expr and all its
+ * children.
+ */
+int
+asn1f_recurse_expr(arg_t *arg, int (*callback)(arg_t *arg)) {
+	asn1p_expr_t *expr = arg->expr;
+	int rvalue = 0;
+	int ret;
+
+	assert(expr);
+
+	/*
+	 * Invoke the callback at this very level.
+	 */
+	ret = callback(arg);
+	RET2RVAL(ret, rvalue);
+
+	/*
+	 * Recursively invoke myself
+	 * to iterate over each element in the tree.
+	 */
+	TQ_FOR(arg->expr, &(expr->members), next) {
+		assert(arg->expr->expr_type != A1TC_INVALID);
+		ret = asn1f_recurse_expr(arg, callback);
+		RET2RVAL(ret, rvalue);
+	}
+
+	arg->expr = expr;	/* Restore original position */
+
+	return rvalue;
+}
+
+
+/*
+ * Check that every child of a given expr has unique name or does not have any.
+ */
+int
+asn1f_check_unique_expr(arg_t *arg,
+		int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
+	asn1p_expr_t *expr;
+	int rvalue = 0;
+
+	TQ_FOR(expr, &(arg->expr->members), next) {
+		if(expr->Identifier) {
+			int ret = asn1f_check_unique_expr_child(arg, expr,
+				opt_compare);
+			if(ret) rvalue = -1;
+		} else {
+			/*
+			 * No point of comparing this child with any other:
+			 * this one does not have a name.
+			 */
+		}
+	}
+
+	return rvalue;
+}
+
+/*
+ * Check that every preceeding child of the given expr is not
+ * having the name of the given one.
+ */
+int
+asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
+		int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
+	asn1p_expr_t *expr;
+	int rvalue = 0;
+
+	assert(child);
+	assert(opt_compare || child->Identifier);
+
+	TQ_FOR(expr, &(arg->expr->members), next) {
+		int ret;
+
+		if(expr == child)
+			break;
+
+		/*
+		 * Compare according to the custom rule or default
+		 * names comparisons.
+		 */
+		if(opt_compare) {
+			ret = opt_compare(expr, child);
+		} else {
+			if(expr->Identifier == NULL
+			|| expr->expr_type == A1TC_EXTENSIBLE)
+				continue;
+			ret = strcasecmp(expr->Identifier, child->Identifier);
+		}
+
+		if(ret == 0) {
+			char *msg;
+			msg = opt_compare
+				?"Expressions clash"
+				:"Identifiers name clash";
+			arg->eh(1,
+				"%s: "
+				"\"%s\" at line %d has similar %s with "
+				"\"%s\" at line %d",
+				msg,
+				expr->Identifier,
+				expr->_lineno,
+				opt_compare?"property":"name",
+				child->Identifier,
+				child->_lineno
+			);
+
+			rvalue = -1;
+		}
+	}
+
+	return rvalue;
+}
+
+int
+asn1f_count_children(asn1p_expr_t *expr) {
+	asn1p_expr_t *child;
+	int count = 0;
+
+	TQ_FOR(child, &(expr->members), next) {
+		count++;
+	}
+
+	return count;
+}
+
diff --git a/libasn1fix/asn1fix_misc.h b/libasn1fix/asn1fix_misc.h
new file mode 100644
index 0000000..e88e432
--- /dev/null
+++ b/libasn1fix/asn1fix_misc.h
@@ -0,0 +1,47 @@
+/*
+ * Miscellaneous functions necessary for several other modules.
+ */
+#ifndef	_ASN1FIX_MISC_H_
+#define	_ASN1FIX_MISC_H_
+
+/*
+ * Return a pointer to the locally held string with human-readable
+ * definition of the value.
+ */
+char const *asn1f_printable_value(asn1p_value_t *);
+
+/*
+ * Return a pointer to the locally held string with human-readable
+ * definition of the reference.
+ */
+char const *asn1f_printable_reference(asn1p_ref_t *);
+
+/*
+ * Recursively invoke a given function over the given expr and all its
+ * children.
+ */
+int asn1f_recurse_expr(arg_t *arg, int (*f)(arg_t *arg));
+
+/*
+ * Check that every child of a given expr has unique name or does not have any.
+ * If opt_compare == NULL, the default comparison of the argument's
+ * names (identifiers) will be performed.
+ */
+int asn1f_check_unique_expr(arg_t *arg,
+		int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b));
+
+/*
+ * Check that every preceeding child of the given expr is not
+ * having the name of the given one.
+ * If opt_compare == NULL, the default comparison of the argument's
+ * names (identifiers) will be performed.
+ */
+int asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
+		int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b));
+
+/*
+ * Return number of children.
+ */
+int asn1f_count_children(asn1p_expr_t *parent);
+
+#endif	/* _ASN1FIX_MISC_H_ */
diff --git a/libasn1fix/asn1fix_param.c b/libasn1fix/asn1fix_param.c
new file mode 100644
index 0000000..0c838cc
--- /dev/null
+++ b/libasn1fix/asn1fix_param.c
@@ -0,0 +1,165 @@
+#include "asn1fix_internal.h"
+
+static int asn1f_parametrize(arg_t *arg, asn1p_expr_t *ex, asn1p_expr_t *ptype);
+static int asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+static asn1p_expr_t *_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs);
+
+int
+asn1f_fix_parametrized_assignment(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *ptype;
+
+	assert(expr->expr_type == A1TC_PARAMETRIZED);
+	assert(expr->reference);
+
+	DEBUG("%s(\"%s\" ::= \"%s\" { %s }) for line %d",
+		__func__, expr->Identifier,
+		asn1f_printable_reference(expr->reference),
+		asn1f_printable_value(expr->value),
+		expr->_lineno);
+
+	/*
+	 * Find the corresponding parametrized type definition.
+	 */
+	DEBUG("Looking for parametrized type definition \"%s\"",
+		asn1f_printable_reference(expr->reference));
+	ptype = asn1f_lookup_symbol(arg, expr->reference, 0);
+	if(ptype == NULL) {
+		DEBUG("%s: missing parametrized type declaration",
+			asn1f_printable_reference(expr->reference));
+		return -1;
+	}
+
+	/*
+	 * Check that the number of arguments which are expected by
+	 * the parametrized type declaration is consistent with the
+	 * number of arguments supplied by the parametrized assignment.
+	 */
+	if(asn1f_count_children(expr) != ptype->params->params_count) {
+		FATAL("Number of actual arguments %d in %s at line %d "
+			"is not equal to number of expected arguments "
+			"%d in %s at line %d",
+			asn1f_count_children(expr),
+			asn1f_printable_reference(expr->reference),
+			expr->_lineno,
+			ptype->params->params_count,
+			ptype->Identifier,
+			ptype->_lineno
+		);
+		return -1;
+	}
+
+	/*
+	 * Perform an expansion of a parametrized assignment.
+	 */
+	return asn1f_parametrize(arg, expr, ptype);
+}
+
+#define	SUBSTITUTE(to, from)	do {		\
+		asn1p_expr_t tmp;		\
+		tmp = *(to);			\
+		*(to) = *(from);		\
+		*(from) = tmp;			\
+		(to)->next = tmp.next;		\
+		memset(&((from)->next), 0,	\
+			sizeof((from)->next));	\
+		asn1p_expr_free(from);		\
+	} while(0)
+
+static int
+asn1f_parametrize(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype) {
+	asn1p_expr_t *nex;
+	void *p;
+	int ret;
+
+	/*
+	 * The algorithm goes like that:
+	 * 1. Replace the expression's type with parametrized type.
+	 * 2. For every child in the parametrized type, import it
+	 * as a child of the expression, replacing all occurences of
+	 * symbols which are defined as parametrized type arguments
+	 * with the actual values.
+	 */
+
+	nex = asn1p_expr_clone(ptype);
+	if(nex == NULL) return -1;
+
+	/*
+	 * Cleanup the new expression so there is no ptype-related
+	 * stuff hanging around.
+	 */
+	p = strdup(expr->Identifier);
+	if(p) {
+		free(nex->Identifier);
+		nex->Identifier = p;
+	} else {
+		asn1p_expr_free(nex);
+		return -1;
+	}
+	asn1p_paramlist_free(nex->params);
+	nex->params = NULL;
+	nex->meta_type = expr->meta_type;
+
+	ret = asn1f_param_process_recursive(arg, nex, ptype, expr);
+	if(ret != 0) {
+		asn1p_expr_free(nex);
+		return ret;
+	}
+
+	SUBSTITUTE(expr, nex);
+
+	return ret;
+}
+
+static int
+asn1f_param_process_recursive(arg_t *arg, asn1p_expr_t *expr, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+	asn1p_expr_t *child;
+
+	TQ_FOR(child, &(expr->members), next) {
+		asn1p_expr_t *ra;
+		asn1p_expr_t *ne;
+
+		ra = _referenced_argument(child->reference, ptype, actargs);
+		if(ra == NULL) continue;
+
+		DEBUG("Substituting parameter for %s %s at line %d",
+			child->Identifier,
+			asn1f_printable_reference(child->reference),
+			child->_lineno
+		);
+
+		assert(child->meta_type == AMT_TYPEREF);
+		assert(child->expr_type == A1TC_REFERENCE);
+
+		ne = asn1p_expr_clone(ra);
+		if(ne == NULL) return -1;
+		assert(ne->Identifier == 0);
+		ne->Identifier = strdup(child->Identifier);
+		if(ne->Identifier == 0) {
+			asn1p_expr_free(ne);
+			return -1;
+		}
+		SUBSTITUTE(child, ne);
+	}
+
+	return 0;
+}
+
+static asn1p_expr_t *
+_referenced_argument(asn1p_ref_t *ref, asn1p_expr_t *ptype, asn1p_expr_t *actargs) {
+	asn1p_expr_t *aa;
+	int i;
+
+	if(ref == NULL || ref->comp_count != 1)
+		return NULL;
+
+	aa = TQ_FIRST(&(actargs->members));
+	for(i = 0; i < ptype->params->params_count;
+				i++, aa = TQ_NEXT(aa, next)) {
+		if(strcmp(ref->components[0].name,
+			ptype->params->params[i].argument) == 0)
+			return aa;
+	}
+
+	return NULL;
+}
diff --git a/libasn1fix/asn1fix_param.h b/libasn1fix/asn1fix_param.h
new file mode 100644
index 0000000..062ad8b
--- /dev/null
+++ b/libasn1fix/asn1fix_param.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_PARAMETRIZATION_H_
+#define	_ASN1FIX_PARAMETRIZATION_H_
+
+int asn1f_fix_parametrized_assignment(arg_t *arg);
+
+#endif	/* _ASN1FIX_PARAMETRIZATION_H_ */
diff --git a/libasn1fix/asn1fix_retrieve.c b/libasn1fix/asn1fix_retrieve.c
new file mode 100644
index 0000000..0dfcce4
--- /dev/null
+++ b/libasn1fix/asn1fix_retrieve.c
@@ -0,0 +1,366 @@
+#include "asn1fix_internal.h"
+
+static asn1p_expr_t *asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr, asn1p_module_t **optm, int type_or_value);
+static int asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name);
+
+
+/*
+ * Lookup a child by its name.
+ */
+asn1p_expr_t *
+asn1f_lookup_child(asn1p_expr_t *tc, const char *name) {
+	asn1p_expr_t *child_tc;
+
+	TQ_FOR(child_tc, &(tc->members), next) {
+		if(child_tc->Identifier
+		&& strcmp(child_tc->Identifier, name) == 0) {
+			return child_tc;
+		}
+	}
+
+	errno = ESRCH;
+	return NULL;
+}
+
+asn1p_module_t *
+asn1f_lookup_in_imports(arg_t *arg, const char *name) {
+	asn1p_module_t *mod;
+	asn1p_xports_t *xp;
+	asn1p_expr_t *tc;
+
+	/*
+	 * Search in which exactly module this name is defined.
+	 */
+	TQ_FOR(xp, &(arg->mod->imports), xp_next) {
+		TQ_FOR(tc, &(xp->members), next) {
+			if(strcmp(name, tc->Identifier) == 0)
+				break;
+		}
+		if(tc) break;
+	}
+	if(xp == NULL) {
+		errno = ESRCH;
+		return NULL;
+	}
+
+	/*
+	 * Okay, right now we have a module name and, hopefully, an OID.
+	 * Search the arg->asn for the specified module.
+	 */
+	mod = asn1f_lookup_module(arg, xp->from, xp->from_oid);
+	if(mod == NULL) {
+		/* ENOENT/ETOOMANYREFS */
+		return NULL;
+	}
+
+	/*
+	 * Check that the EXPORTS section of this module contains
+	 * the symbol we care about, or it is EXPORTS ALL.
+	 */
+	if(asn1f_compatible_with_exports(arg, mod, name)) {
+		errno = EPERM;
+		return NULL;
+	}
+
+	return mod;
+}
+
+asn1p_module_t *
+asn1f_lookup_module(arg_t *arg, const char *module_name, asn1p_oid_t *oid) {
+	asn1p_module_t *mod;
+
+	assert(module_name);
+
+	/*
+	 * If OID is given, the module_name is unused.
+	 * If OID is not given, the module_name may mean
+	 * either the real module's name, or the symbol which is the
+	 * result of renaming. Check this first.
+	 */
+	if(oid == 0) {
+		asn1p_xports_t *xp;
+		/*
+		 * Check inside the IMPORTS section for possible renaming.
+		 * Renaming practically means that a module_name is mentioned
+		 * somewhere in the IMPORTS section AND OID is given.
+		 */
+		TQ_FOR(xp, &(arg->mod->imports), xp_next) {
+			if(strcmp(module_name, xp->from))
+				continue;
+			if(oid) {
+				FATAL("Ambiguous reference: "
+					"%s "
+					"matches several modules",
+					module_name);
+				errno = ETOOMANYREFS;
+				return NULL;
+			}
+			/*
+			 * Yes, there is a renaming.
+			 * Make lookup use OID instead.
+			 */
+			oid = xp->from_oid;
+		}
+	}
+
+	/*
+	 * Perform lookup using OID or module_name.
+	 */
+	TQ_FOR(mod, &(arg->asn->modules), mod_next) {
+		if(oid) {
+			if(mod->module_oid) {
+				if(asn1p_oid_compare(oid,
+					mod->module_oid)) {
+					continue;
+				} else {
+					/* Match! Even if name doesn't. */
+					return mod;
+				}
+			} else {
+				/* Not match, even if name is the same. */
+				continue;
+			}
+		}
+	
+		if(strcmp(module_name, mod->Identifier) == 0)
+			return mod;
+	}
+
+	DEBUG("\tModule \"%s\" not found", module_name);
+
+	errno = ENOENT;
+	return NULL;
+}
+
+
+
+asn1p_expr_t *
+asn1f_lookup_symbol(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **module_r) {
+	asn1p_expr_t *ref_tc;			/* Referenced tc */
+	asn1p_module_t *src_mod;
+	char *modulename;
+	char *identifier;
+
+	/*
+	 * First of all, a reference to a symbol may be specified
+	 * using several possible forms:
+	 * a) simple identifier
+	 *	v INTEGER ::= value
+	 * b) external reference
+	 * 	v INTEGER ::= Module1.value
+	 * c) class-related stuff (the most complex stuff)
+	 * 	v ::= <[A-Z][A-Z0-9a-z-]*>.&<[A-Z0-9a-z-]+>.
+	 * All other forms are not implemented at this moment.
+	 */
+
+	DEBUG("%s(%s) in %s for line %d", __func__,
+		asn1f_printable_reference(ref),
+		arg->mod->Identifier,
+		ref->_lineno);
+
+	if(ref->comp_count == 1) {
+		modulename = NULL;
+		identifier = ref->components[0].name;
+	} else if(ref->comp_count == 2
+		&& ref->components[1].name[0] != '&') {
+		modulename = ref->components[0].name;
+		identifier = ref->components[1].name;
+	} else if(ref->comp_count > 1
+		&& isupper(ref->components[0].name[0])
+		&& ref->components[1].name[0] == '&') {
+		asn1p_expr_t *extract;
+		/*
+		 * This is a reference to a CLASS-related stuff.
+		 * Employ a separate function for that.
+		 */
+		extract = asn1f_class_access(arg, ref, module_r);
+		
+		return extract;
+	} else {
+		DEBUG("\tToo many components: %d", ref->comp_count);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	/*
+	 * If module name is specified explicitly
+	 * OR the current module's IMPORTS clause contains the identifier,
+	 * fetch that module.
+	 */
+	if(modulename) {
+		src_mod = asn1f_lookup_module(arg, modulename, 0);
+		if(src_mod == NULL) {
+			FATAL("Module \"%s\" "
+				"mentioned at line %d is not found",
+				modulename, ref->_lineno);
+			return NULL;
+		}
+
+		/*
+		 * Check that the EXPORTS section of this module contains
+		 * the symbol we care about, or it is EXPORTS ALL.
+		 */
+		if(asn1f_compatible_with_exports(arg, src_mod, identifier)) {
+			errno = EPERM;
+			return NULL;
+		}
+	} else {
+		src_mod = asn1f_lookup_in_imports(arg, identifier);
+		if(src_mod == NULL && errno != ESRCH) {
+			/*
+			 * Return only of the name was not found.
+			 * If module was not found or more serious error
+			 * encountered, just return preserving the errno.
+			 */
+			return NULL;
+		}
+	}
+
+	if(src_mod == 0) src_mod = arg->mod;
+
+	/*
+	 * Now we know where to search for a value.
+	 */
+	TQ_FOR(ref_tc, &(src_mod->members), next) {
+		if(ref_tc->Identifier)
+		if(strcmp(ref_tc->Identifier, identifier) == 0)
+			break;
+	}
+	if(ref_tc == NULL) {
+		DEBUG("Module \"%s\" does not contain \"%s\" "
+			"mentioned at line %d",
+			src_mod->Identifier,
+			identifier,
+			ref->_lineno
+		);
+		errno = ESRCH;
+		return NULL;
+	}
+
+	if(module_r)
+		*module_r = src_mod;
+
+	return ref_tc;
+}
+
+
+asn1p_expr_t *
+asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *expr,
+		asn1p_module_t **optm) {
+	return asn1f_find_terminal_thing(arg, expr, optm, 0);
+}
+
+asn1p_expr_t *
+asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *expr,
+		asn1p_module_t **optm) {
+	return asn1f_find_terminal_thing(arg, expr, optm, 1);
+}
+
+static asn1p_expr_t *
+asn1f_find_terminal_thing(arg_t *arg, asn1p_expr_t *expr,
+	asn1p_module_t **optm, int type_or_value) {
+	asn1p_module_t *mod;
+	asn1p_ref_t *ref;
+	asn1p_expr_t *tc;
+
+	if(type_or_value) {
+		/* VALUE */
+		assert(expr->meta_type == AMT_VALUE);
+		assert(expr->value);
+		if(expr->value->type != ATV_REFERENCED) {
+			/* Expression is a terminal value itself */
+			if(optm) *optm = arg->mod;
+			return expr;
+		}
+		ref = expr->value->value.reference;
+	} else {
+		/* TYPE */
+		if(expr->expr_type != A1TC_REFERENCE) {
+			/* Expression is a terminal type itself */
+			if(optm) *optm = arg->mod;
+			return expr;
+		}
+		ref = expr->reference;
+	}
+
+	DEBUG("%s:%s(%s->%s) for line %d",
+		__func__, type_or_value?"VALUE":"TYPE",
+		expr->Identifier, asn1f_printable_reference(ref),
+		expr->_lineno);
+
+	assert(ref);
+
+	/*
+	 * Lookup inside the type itself (ENUMERATED, INTEGER, etc).
+	 */
+	if(type_or_value) {
+		asn1p_expr_t *val_type_tc;
+		val_type_tc = asn1f_find_terminal_type(arg, expr, 0);
+		if(val_type_tc
+		&& asn1f_look_value_in_type(arg, val_type_tc, expr))
+			return NULL;
+		if(expr->value->type != ATV_REFERENCED) {
+			if(optm) *optm = arg->mod;
+			return expr;
+		}
+		assert(ref == expr->value->value.reference);
+		ref = expr->value->value.reference;
+	}
+
+	/*
+	 * Lookup inside the default module.
+	 */
+	tc = asn1f_lookup_symbol(arg, ref, &mod);
+	if(tc == NULL) {
+		DEBUG("\tSymbol \"%s\" not found",
+			asn1f_printable_reference(ref));
+		return NULL;
+	}
+
+	/*
+	 * Recursive loops detection.
+	 */
+	if(tc->_mark & TM_RECURSION) {
+		DEBUG("Recursion loop detected for %s at line %d",
+			asn1f_printable_reference(ref), ref->_lineno);
+		errno = EPERM;
+		return NULL;
+	}
+
+	tc->_mark |= TM_RECURSION;
+	WITH_MODULE(mod,
+		expr = asn1f_find_terminal_thing(arg, tc, optm, type_or_value));
+	tc->_mark &= ~TM_RECURSION;
+
+	return expr;
+}
+
+/*
+ * Make sure that the specified name is present or otherwise does
+ * not contradict with the EXPORTS clause of the specified module.
+ */
+static int
+asn1f_compatible_with_exports(arg_t *arg, asn1p_module_t *mod, const char *name) {
+	asn1p_xports_t *exports;
+	asn1p_expr_t *item;
+
+	assert(mod);
+	assert(name);
+
+	exports = TQ_FIRST(&(mod->exports));
+	if(exports == NULL) {
+		/* No EXPORTS section or EXPORTS ALL; */
+		return 0;
+	}
+
+	TQ_FOR(item, &(exports->members), next) {
+		if(strcmp(item->Identifier, name) == 0)
+			return 0;
+	}
+
+	DEBUG("Symbol \"%s\" contradicts with EXPORTS of module %s",
+		name, mod->Identifier);
+
+	errno = ESRCH;
+	return -1;
+}
diff --git a/libasn1fix/asn1fix_retrieve.h b/libasn1fix/asn1fix_retrieve.h
new file mode 100644
index 0000000..47aa0a5
--- /dev/null
+++ b/libasn1fix/asn1fix_retrieve.h
@@ -0,0 +1,73 @@
+/*
+ * Miscellaneous functions necessary for several other modules.
+ */
+#ifndef	_ASN1FIX_RETRIEVE_H_
+#define	_ASN1FIX_RETRIEVE_H_
+
+/*
+ * Simple search for the label in the descendants of the given node.
+ * ERRORS:
+ * NULL/ESRCH
+ */
+asn1p_expr_t *asn1f_lookup_child(asn1p_expr_t *tc, const char *name);
+
+/*
+ * Return a module which contain a specified name, as stated in appropriate
+ * IMPORTS section of the current module (arg->mod).
+ *
+ * RETURN VALUES:
+ * NULL/ESRCH:	The name was not found in IMPORTS section.
+ * NULL/EPERM:	The name was not found in EXPORTS section of the source module.
+ * Also, NULL with errno values defined by asn1f_lookup_module().
+ */
+asn1p_module_t *asn1f_lookup_in_imports(arg_t *arg, const char *name);
+
+/*
+ * Return a module by its name or optional OID.
+ *
+ * RETURN VALUES:
+ * NULL/ENOENT:	No module was found by the specified name and oid
+ * NULL/ETOOMANYREFS:	Several modules are matching the specified name and oid
+ */
+asn1p_module_t *asn1f_lookup_module(arg_t *arg,
+		const char *module_name,
+		asn1p_oid_t *module_oid);
+
+/*
+ * Return the reference to a destination of the given reference,
+ * symbol lookup. Not a recursive function.
+ * Optional module reference may be assigned a module in which the
+ * particular expr was found.
+ */
+asn1p_expr_t *asn1f_lookup_symbol(arg_t *arg, asn1p_ref_t *ref,
+		asn1p_module_t **opt_module_r);
+
+/*
+ * Recursively find the original type for the given expression.
+ * i.e.:
+ * If the original specification defines
+ * 	v Type1 ::= 5
+ * 	Type1 ::= Type2 (1..5)
+ * 	Type3 ::= Type4 (2..7)
+ * 	Type4 ::= INTEGER (1..10)
+ * Then this function, given the the first expression as an argument,
+ * would return an expression for Type4.
+ * WARNING: No attempts are made to honor constraints at this moment.
+ */
+asn1p_expr_t *asn1f_find_terminal_type(arg_t *arg, asn1p_expr_t *tc,
+	asn1p_module_t **opt_module_r);
+
+/*
+ * Recursively find the original value for the given expression.
+ * i.e.:
+ * If the original specification defines
+ * 	v Type1 ::= value
+ * 	value Type2 ::= value2
+ * 	value2 Type3 ::= 3
+ * Then this function will return the expression for value2 if given
+ * the v as an argment.
+ */
+asn1p_expr_t *asn1f_find_terminal_value(arg_t *arg, asn1p_expr_t *tc,
+	asn1p_module_t **opt_module_r);
+
+#endif	/* _ASN1FIX_RETRIEVE_H_ */
diff --git a/libasn1fix/asn1fix_tags.c b/libasn1fix/asn1fix_tags.c
new file mode 100644
index 0000000..ed8c19f
--- /dev/null
+++ b/libasn1fix/asn1fix_tags.c
@@ -0,0 +1,47 @@
+#include "asn1fix_internal.h"
+
+int
+asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag) {
+	int ret;
+
+	if(expr->tag.tag_class != TC_NOCLASS) {
+		*tag = expr->tag;
+		return 0;
+	}
+
+	if(expr->expr_type == A1TC_EXTENSIBLE) {
+		memset(tag, 0, sizeof(*tag));
+		tag->tag_class = -1;
+		return 0;
+	}
+
+	if(expr->meta_type == AMT_TYPE) {
+		memset(tag, 0, sizeof(*tag));
+		tag->tag_class = TC_UNIVERSAL;
+		tag->tag_value = expr_type2uclass_value[expr->expr_type];
+		return (tag->tag_value == 0) ? -1 : 0;
+	}
+
+	if(expr->meta_type == AMT_TYPEREF) {
+		arg_t arg;
+
+		memset(&arg, 0, sizeof(arg));
+		arg.asn = asn;
+		arg.mod = mod;
+		arg.expr = expr;
+
+		expr = asn1f_lookup_symbol(&arg, expr->reference, &mod);
+		if(expr == NULL) return -1;
+
+		if(expr->_mark & TM_RECURSION)
+			return -1;
+
+		expr->_mark |= TM_RECURSION;
+		ret = asn1f_fetch_tag(asn, mod, expr, tag);
+		expr->_mark &= ~TM_RECURSION;
+		return ret;
+	}
+
+	return -1;
+}
+
diff --git a/libasn1fix/asn1fix_tags.h b/libasn1fix/asn1fix_tags.h
new file mode 100644
index 0000000..9d3595b
--- /dev/null
+++ b/libasn1fix/asn1fix_tags.h
@@ -0,0 +1,6 @@
+#ifndef	_ASN1FIX_TAGS_H_
+#define	_ASN1FIX_TAGS_H_
+
+int asn1f_fetch_tag(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, struct asn1p_type_tag_s *tag);
+
+#endif	/* _ASN1FIX_TAGS_H_ */
diff --git a/libasn1fix/asn1fix_value.c b/libasn1fix/asn1fix_value.c
new file mode 100644
index 0000000..a22fd3d
--- /dev/null
+++ b/libasn1fix/asn1fix_value.c
@@ -0,0 +1,159 @@
+#include "asn1fix_internal.h"
+
+static int _asn1f_copy_value(arg_t *arg, asn1p_expr_t *to,asn1p_expr_t *from);
+
+int
+asn1f_value_resolve(arg_t *arg, asn1p_expr_t *expr) {
+	asn1p_module_t *val_mod;
+	asn1p_expr_t *val_type_expr;
+	asn1p_expr_t *value_expr;
+	asn1p_expr_t *type_expr;
+	int ret;
+
+	/* Make sure this IS a value assignment */
+	assert(expr->meta_type == AMT_VALUE);
+	assert(expr->value);
+
+	DEBUG("%s(=\"%s\", %x)", __func__,
+		asn1f_printable_value(expr->value), expr->expr_type);
+
+	/*
+	 * 1. Find the terminal type for this assignment.
+	 */
+	type_expr = asn1f_find_terminal_type(arg, expr, 0);
+	if(type_expr == 0) {
+		DEBUG("\tTerminal type for %s not found", expr->Identifier);
+		return -1;
+	}
+
+	if(asn1f_look_value_in_type(arg, type_expr, expr) == -1)
+		return -1;
+
+	/*
+	 * 2. Find the terminal value also.
+	 */
+	value_expr = asn1f_find_terminal_value(arg, expr, &val_mod);
+	if(value_expr) {
+		DEBUG("\tTerminal value for %s->%s is %s at line %d",
+			expr->Identifier, asn1f_printable_value(expr->value),
+			value_expr->Identifier, value_expr->_lineno);
+	} else {
+		DEBUG("\tTerminal value for %s->%s not found",
+			expr->Identifier, asn1f_printable_value(expr->value));
+		return -1;
+	}
+
+	/*
+	 * 3. Find the _type_ of a _terminal value_.
+	 */
+	WITH_MODULE(val_mod,
+		val_type_expr = asn1f_find_terminal_type(arg, value_expr, 0));
+	if(val_type_expr) {
+		DEBUG("\tTerminal type of value %s->%s is %s at line %d",
+			expr->Identifier, asn1f_printable_value(expr->value),
+			val_type_expr->Identifier, val_type_expr->_lineno);
+	} else {
+		DEBUG("\tTerminal type of value %s->%s not found",
+			expr->Identifier, asn1f_printable_value(expr->value));
+		return -1;
+	}
+
+	/*
+	 * 4. Check compatibility between the type of the current expression
+	 * and the type of the discovered value.
+	 */
+	ret = asn1f_check_type_compatibility(arg, type_expr, val_type_expr);
+	if(ret == -1) {
+		DEBUG("\tIncompatible type of %s at %d with %s at %d",
+			type_expr->Identifier, type_expr->_lineno,
+			val_type_expr->Identifier, val_type_expr->_lineno);
+		return -1;
+	}
+
+	if(asn1f_look_value_in_type(arg, val_type_expr, expr) == -1)
+		return -1;
+
+	/*
+	 * 5. Copy value from the terminal value into the current expression.
+	 */
+	ret = _asn1f_copy_value(arg, expr, value_expr);
+	if(ret == -1) {
+		DEBUG("\tValue %s cannot be copied from line %d to line %d",
+			asn1f_printable_value(value_expr->value),
+			value_expr->_lineno, expr->_lineno);
+		return -1;
+	}
+
+	DEBUG("\tFinal value for \"%s\" at line %d is %s",
+		expr->Identifier, expr->_lineno,
+		asn1f_printable_value(expr->value));
+
+	return 0;
+}
+
+static int
+_asn1f_copy_value(arg_t *arg, asn1p_expr_t *to, asn1p_expr_t *from) {
+	asn1p_value_t *v;
+
+	v = asn1p_value_clone(from->value);
+	if(v) {
+		asn1p_value_free(to->value);
+		to->value = v;
+		DEBUG("Copied value %s from \"%s\" on line %d "
+			"to \"%s\" on line %d",
+			asn1f_printable_value(v),
+			from->Identifier,
+			from->_lineno,
+			to->Identifier,
+			to->_lineno
+		);
+		return 0;
+	} else {
+		return -1;
+	}
+}
+
+int
+asn1f_look_value_in_type(arg_t *arg,
+		asn1p_expr_t *type_expr,
+		asn1p_expr_t *value_expr) {
+	asn1p_expr_t *child_expr;
+	char *identifier;
+
+	if(value_expr->value->type != ATV_REFERENCED
+	|| value_expr->value->value.reference->comp_count != 1)
+		return 0;
+	if(type_expr->expr_type != ASN_BASIC_INTEGER
+	&& type_expr->expr_type != ASN_BASIC_ENUMERATED)
+		return 0;
+
+	DEBUG("%s(for %s in %s %x) for line %d", __func__,
+		asn1f_printable_value(value_expr->value),
+		type_expr->Identifier,
+		type_expr->expr_type,
+		value_expr->_lineno);
+
+	/*
+	 * Look into the definitions of the type itself:
+	 * Type1 ::= INTEGER { a(1), b(2) }
+	 * value Type1 = b	-- will assign 2
+	 */
+	identifier = value_expr->value->value.reference->components[0].name;
+
+	child_expr = asn1f_lookup_child(type_expr, identifier);
+	DEBUG("\tLooking into a type %s at line %d for %s at line %d: %s",
+		type_expr->Identifier, type_expr->_lineno,
+		identifier, value_expr->_lineno,
+		child_expr
+			? asn1f_printable_value(child_expr->value)
+			: "<not found>"
+		);
+
+	if(child_expr && child_expr->value) {
+		if(_asn1f_copy_value(arg, value_expr, child_expr))
+			return -1;
+		/* Fall through */
+	}
+
+	return 0;
+}
diff --git a/libasn1fix/asn1fix_value.h b/libasn1fix/asn1fix_value.h
new file mode 100644
index 0000000..7234035
--- /dev/null
+++ b/libasn1fix/asn1fix_value.h
@@ -0,0 +1,28 @@
+/*
+ * Functions related with processing values.
+ */
+#ifndef	_ASN1FIX_VALUE_H_
+#define	_ASN1FIX_VALUE_H_
+
+/*
+ * Resolve the value given by reference.
+ * This function also takes a parameter which specifies the desired
+ * value's type.
+ * 
+ * RETURN VALUES:
+ * 0:		Value resolved successfully.
+ * -1/EPERM:	Recursive looping detected.
+ * -1/EEXIST:	Reference is not compatible with the desired type.
+ * -1/ESRCH:	Cannot find the terminal reference.
+ */
+int asn1f_value_resolve(arg_t *arg, asn1p_expr_t *tc);
+
+/*
+ * Check if a value in value_expr refers to the enumeration or integer element
+ * within the type provided. If yes, it will replace referenced value with
+ * the appropriate inline value.
+ */
+int asn1f_look_value_in_type(arg_t *arg,
+		asn1p_expr_t *type_expr, asn1p_expr_t *value_expr);
+
+#endif	/* _ASN1FIX_VALUE_H_ */
diff --git a/libasn1fix/check_fixer.c b/libasn1fix/check_fixer.c
new file mode 100644
index 0000000..21c5b12
--- /dev/null
+++ b/libasn1fix/check_fixer.c
@@ -0,0 +1,313 @@
+#undef	NDEBUG
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sysexits.h>
+
+#include "asn1fix.h"
+#include "asn1fix_internal.h"
+
+static int check(const char *fname,
+	enum asn1p_flags parser_flags,
+	enum asn1f_flags fixer_flags);
+static int post_fix_check(asn1p_t *asn);
+static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr);
+
+int
+main(int ac, char **av) {
+	struct dirent *dp;
+	DIR *dir;
+	int failed = 0;
+	int completed = 0;
+	enum asn1p_flags parser_flags = A1P_NOFLAGS;
+	enum asn1f_flags fixer_flags  = A1F_NOFLAGS;
+	int ret;
+
+	/*
+	 * Just in case when one decides that some flags better be
+	 * enabled during `ASN1_FIXER_FLAGS=1 make check` or some
+	 * similar usage.
+	 */
+	if(getenv("ASN1_PARSER_FLAGS"))
+		parser_flags = atoi(getenv("ASN1_PARSER_FLAGS"));
+	if(getenv("ASN1_FIXER_FLAGS"))
+		fixer_flags = atoi(getenv("ASN1_FIXER_FLAGS"));
+
+	/*
+	 * Go into a directory with tests.
+	 */
+	if(ac <= 1) {
+		fprintf(stderr, "Testing in ./tests...\n");
+		ret = chdir("../tests");
+		assert(ret == 0);
+		dir = opendir(".");
+		assert(dir);
+	} else {
+		dir = 0;
+	}
+
+	/*
+	 * Scan every *.asn1 file and try to parse and fix it.
+	 */
+	if(dir) {
+		while((dp = readdir(dir))) {
+			int len = strlen(dp->d_name);
+			if(len && strcmp(dp->d_name + len - 5, ".asn1") == 0) {
+				ret = check(dp->d_name,
+					parser_flags, fixer_flags);
+				if(ret) {
+					fprintf(stderr,
+						"FAILED: %s\n",
+						dp->d_name);
+					failed++;
+				}
+				completed++;
+			}
+		}
+		closedir(dir);
+
+		fprintf(stderr,
+			"Tests COMPLETED: %d\n"
+			"Tests FAILED:    %d\n"
+			,
+			completed, failed
+		);
+	} else {
+		int i;
+		for(i = 1; i < ac; i++) {
+			ret = check(av[i], parser_flags, fixer_flags);
+			if(ret) {
+				fprintf(stderr, "FAILED: %s\n", av[i]);
+				failed++;
+			}
+			completed++;
+		}
+	}
+
+	if(completed == 0) {
+		fprintf(stderr, "No tests defined?!\n");
+		exit(EX_NOINPUT);
+	}
+
+	if(failed)
+		exit(EX_DATAERR);
+	return 0;
+}
+
+static int
+check(const char *fname,
+		enum asn1p_flags parser_flags,
+		enum asn1f_flags fixer_flags) {
+	asn1p_t *asn;
+	int expected_parseable;		/* Is it expected to be parseable? */
+	int expected_fix_code;		/* What code a fixer must return */
+	int r_value = 0;
+
+	/*
+	 * Figure out how the processing should go by inferring
+	 * expectations from the file name.
+	 */
+	if(strstr(fname, "-OK.")) {
+		expected_parseable = 1;
+		expected_fix_code  = 0;
+	} else if(strstr(fname, "-NP.")) {
+		expected_parseable = 0;
+		expected_fix_code  = 123;	/* Does not matter */
+	} else if(strstr(fname, "-SE.")) {
+		expected_parseable = 1;
+		expected_fix_code  = -1;	/* Semantically incorrect */
+	} else if(strstr(fname, "-SW.")) {
+		expected_parseable = 1;
+		expected_fix_code  = 1;	/* Semantically suspicious */
+	} else {
+		fprintf(stderr, "%s: Invalid file name format\n", fname);
+		return -1;
+	}
+
+	fprintf(stderr, "[=> %s]\n", fname);
+
+	/*
+	 * Perform low-level parsing.
+	 */
+	if(!expected_parseable)
+		fprintf(stderr, "Expecting error...\n");
+	asn = asn1p_parse_file(fname, parser_flags);
+	if(asn == NULL) {
+		if(expected_parseable) {
+			fprintf(stderr, "Cannot parse file \"%s\"\n", fname);
+			r_value = -1;
+		} else {
+			fprintf(stderr,
+				"Previous error is EXPECTED, no worry\n");
+		}
+	} else if(!expected_parseable) {
+		fprintf(stderr,
+			"The file \"%s\" is not expected to be parseable, "
+			"yet parsing was successfull!\n", fname);
+		r_value = -1;
+	}
+
+	/*
+	 * Perform semantical checks and fixes.
+	 */
+	if(asn && r_value == 0) {
+		int ret;
+
+		if(expected_fix_code)
+			fprintf(stderr, "Expecting some problems...\n");
+
+		ret = asn1f_process(asn, fixer_flags, 0);
+		if(ret) {
+			if(ret == expected_fix_code) {
+				fprintf(stderr,
+					"Previous error is EXPECTED, "
+					"no worry\n");
+			} else {
+				fprintf(stderr,
+					"Cannot process file \"%s\": %d\n",
+					fname, ret);
+				r_value = -1;
+		}
+		} else if(ret != expected_fix_code) {
+			fprintf(stderr,
+				"File \"%s\" is expected "
+				"to be semantically incorrect, "
+				"yet processing was successful!\n",
+				fname);
+			r_value = -1;
+		}
+	}
+
+	/*
+	 * Check validity of some values, if grammar has special
+	 * instructions for that.
+	 */
+	if(asn && r_value == 0) {
+		if(post_fix_check(asn))
+			r_value = -1;
+	}
+
+	/*
+	 * TODO: destroy the asn.
+	 */
+
+	return r_value;
+}
+
+
+static int
+post_fix_check(asn1p_t *asn) {
+	asn1p_module_t *mod;
+	asn1p_expr_t *expr;
+	int r_value = 0;
+
+	TQ_FOR(mod, &(asn->modules), mod_next) {
+		TQ_FOR(expr, &(mod->members), next) {
+			assert(expr->Identifier);
+			if(strncmp(expr->Identifier, "check-", 6) == 0) {
+				if(post_fix_check_element(mod, expr))
+					r_value = -1;
+			}
+		}
+	}
+
+	return r_value;
+}
+
+
+static int
+post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) {
+	asn1p_expr_t *expr = NULL;
+	char *name;
+	asn1p_value_t *value;
+
+	if(check_expr->expr_type != ASN_BASIC_INTEGER
+	|| check_expr->meta_type != AMT_VALUE) {
+		fprintf(stderr,
+			"CHECKER: Unsupported type of \"%s\" value: "
+			"%d at line %d of %s\n",
+			check_expr->Identifier,
+			check_expr->expr_type,
+			check_expr->_lineno,
+			mod->source_file_name
+		);
+		return -1;
+	}
+
+	assert(check_expr->meta_type == AMT_VALUE);
+
+	value = check_expr->value;
+	if(value == NULL || value->type != ATV_INTEGER) {
+		fprintf(stderr,
+			"CHECKER: Unsupported value type of \"%s\": "
+			"%d at line %d of %s\n",
+			check_expr->Identifier,
+			value?value->type:-1,
+			expr->_lineno,
+			mod->source_file_name
+		);
+		return -1;
+	}
+
+	name = check_expr->Identifier + sizeof("check-") - 1;
+
+	/*
+	 * Scan in search for the original.
+	 */
+	TQ_FOR(expr, &(mod->members), next) {
+		if(strcmp(expr->Identifier, name) == 0)
+			break;
+	}
+
+	if(expr == NULL) {
+		fprintf(stderr,
+			"CHECKER: Value \"%s\" requested by "
+			"\"check-%s\" at line %d of %s is not found!\n",
+			name, name, check_expr->_lineno,
+			mod->source_file_name
+		);
+		return -1;
+	}
+
+	if(0 && expr->expr_type != check_expr->expr_type) {
+		fprintf(stderr,
+			"CHECKER: Value type of \"%s\" (=%d) at line %d "
+			"does not have desired type %d as requested by "
+			"\"check-%s\" in %s\n",
+			expr->Identifier,
+			expr->expr_type,
+			expr->_lineno,
+			check_expr->expr_type,
+			name,
+			mod->source_file_name
+		);
+		return -1;
+	}
+
+	if(expr->value == NULL
+	|| expr->value->type != value->type) {
+		fprintf(stderr,
+			"CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d "
+			"does not have desired type %d as requested by "
+			"\"check-%s\" in %s\n",
+			expr->Identifier,
+			asn1f_printable_value(expr->value),
+			expr->value->type,
+			expr->_lineno,
+			value->type,
+			name,
+			mod->source_file_name
+		);
+		return -1;
+	}
+
+	assert(value->type = ATV_INTEGER);
+
+	return 0;
+}
+
+