Home | History | Annotate | Line # | Download | only in radeon
mkregtable.c revision 1.2
      1 /*	$NetBSD: mkregtable.c,v 1.2 2018/08/27 04:58:36 riastradh Exp $	*/
      2 
      3 /* utility to create the register check tables
      4  * this includes inlined list.h safe for userspace.
      5  *
      6  * Copyright 2009 Jerome Glisse
      7  * Copyright 2009 Red Hat Inc.
      8  *
      9  * Authors:
     10  * 	Jerome Glisse
     11  * 	Dave Airlie
     12  */
     13 
     14 #include <sys/cdefs.h>
     15 __KERNEL_RCSID(0, "$NetBSD: mkregtable.c,v 1.2 2018/08/27 04:58:36 riastradh Exp $");
     16 
     17 #include <sys/types.h>
     18 #include <stdlib.h>
     19 #include <string.h>
     20 #include <stdio.h>
     21 #include <regex.h>
     22 #include <libgen.h>
     23 
     24 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
     25 /**
     26  * container_of - cast a member of a structure out to the containing structure
     27  * @ptr:    the pointer to the member.
     28  * @type:   the type of the container struct this is embedded in.
     29  * @member: the name of the member within the struct.
     30  *
     31  */
     32 #define container_of(ptr, type, member) ({          \
     33 	const typeof(((type *)0)->member)*__mptr = (ptr);    \
     34 		     (type *)((char *)__mptr - offsetof(type, member)); })
     35 
     36 /*
     37  * Simple doubly linked list implementation.
     38  *
     39  * Some of the internal functions ("__xxx") are useful when
     40  * manipulating whole lists rather than single entries, as
     41  * sometimes we already know the next/prev entries and we can
     42  * generate better code by using them directly rather than
     43  * using the generic single-entry routines.
     44  */
     45 
     46 struct list_head {
     47 	struct list_head *next, *prev;
     48 };
     49 
     50 #define LIST_HEAD_INIT(name) { &(name), &(name) }
     51 
     52 #define LIST_HEAD(name) \
     53 	struct list_head name = LIST_HEAD_INIT(name)
     54 
     55 static inline void INIT_LIST_HEAD(struct list_head *list)
     56 {
     57 	list->next = list;
     58 	list->prev = list;
     59 }
     60 
     61 /*
     62  * Insert a new entry between two known consecutive entries.
     63  *
     64  * This is only for internal list manipulation where we know
     65  * the prev/next entries already!
     66  */
     67 #ifndef CONFIG_DEBUG_LIST
     68 static inline void __list_add(struct list_head *new,
     69 			      struct list_head *prev, struct list_head *next)
     70 {
     71 	next->prev = new;
     72 	new->next = next;
     73 	new->prev = prev;
     74 	prev->next = new;
     75 }
     76 #else
     77 extern void __list_add(struct list_head *new,
     78 		       struct list_head *prev, struct list_head *next);
     79 #endif
     80 
     81 /**
     82  * list_add - add a new entry
     83  * @new: new entry to be added
     84  * @head: list head to add it after
     85  *
     86  * Insert a new entry after the specified head.
     87  * This is good for implementing stacks.
     88  */
     89 static inline void list_add(struct list_head *new, struct list_head *head)
     90 {
     91 	__list_add(new, head, head->next);
     92 }
     93 
     94 /**
     95  * list_add_tail - add a new entry
     96  * @new: new entry to be added
     97  * @head: list head to add it before
     98  *
     99  * Insert a new entry before the specified head.
    100  * This is useful for implementing queues.
    101  */
    102 static inline void list_add_tail(struct list_head *new, struct list_head *head)
    103 {
    104 	__list_add(new, head->prev, head);
    105 }
    106 
    107 /*
    108  * Delete a list entry by making the prev/next entries
    109  * point to each other.
    110  *
    111  * This is only for internal list manipulation where we know
    112  * the prev/next entries already!
    113  */
    114 static inline void __list_del(struct list_head *prev, struct list_head *next)
    115 {
    116 	next->prev = prev;
    117 	prev->next = next;
    118 }
    119 
    120 /**
    121  * list_del - deletes entry from list.
    122  * @entry: the element to delete from the list.
    123  * Note: list_empty() on entry does not return true after this, the entry is
    124  * in an undefined state.
    125  */
    126 #ifndef CONFIG_DEBUG_LIST
    127 static inline void list_del(struct list_head *entry)
    128 {
    129 	__list_del(entry->prev, entry->next);
    130 	entry->next = (void *)0xDEADBEEF;
    131 	entry->prev = (void *)0xBEEFDEAD;
    132 }
    133 #else
    134 extern void list_del(struct list_head *entry);
    135 #endif
    136 
    137 /**
    138  * list_replace - replace old entry by new one
    139  * @old : the element to be replaced
    140  * @new : the new element to insert
    141  *
    142  * If @old was empty, it will be overwritten.
    143  */
    144 static inline void list_replace(struct list_head *old, struct list_head *new)
    145 {
    146 	new->next = old->next;
    147 	new->next->prev = new;
    148 	new->prev = old->prev;
    149 	new->prev->next = new;
    150 }
    151 
    152 static inline void list_replace_init(struct list_head *old,
    153 				     struct list_head *new)
    154 {
    155 	list_replace(old, new);
    156 	INIT_LIST_HEAD(old);
    157 }
    158 
    159 /**
    160  * list_del_init - deletes entry from list and reinitialize it.
    161  * @entry: the element to delete from the list.
    162  */
    163 static inline void list_del_init(struct list_head *entry)
    164 {
    165 	__list_del(entry->prev, entry->next);
    166 	INIT_LIST_HEAD(entry);
    167 }
    168 
    169 /**
    170  * list_move - delete from one list and add as another's head
    171  * @list: the entry to move
    172  * @head: the head that will precede our entry
    173  */
    174 static inline void list_move(struct list_head *list, struct list_head *head)
    175 {
    176 	__list_del(list->prev, list->next);
    177 	list_add(list, head);
    178 }
    179 
    180 /**
    181  * list_move_tail - delete from one list and add as another's tail
    182  * @list: the entry to move
    183  * @head: the head that will follow our entry
    184  */
    185 static inline void list_move_tail(struct list_head *list,
    186 				  struct list_head *head)
    187 {
    188 	__list_del(list->prev, list->next);
    189 	list_add_tail(list, head);
    190 }
    191 
    192 /**
    193  * list_is_last - tests whether @list is the last entry in list @head
    194  * @list: the entry to test
    195  * @head: the head of the list
    196  */
    197 static inline int list_is_last(const struct list_head *list,
    198 			       const struct list_head *head)
    199 {
    200 	return list->next == head;
    201 }
    202 
    203 /**
    204  * list_empty - tests whether a list is empty
    205  * @head: the list to test.
    206  */
    207 static inline int list_empty(const struct list_head *head)
    208 {
    209 	return head->next == head;
    210 }
    211 
    212 /**
    213  * list_empty_careful - tests whether a list is empty and not being modified
    214  * @head: the list to test
    215  *
    216  * Description:
    217  * tests whether a list is empty _and_ checks that no other CPU might be
    218  * in the process of modifying either member (next or prev)
    219  *
    220  * NOTE: using list_empty_careful() without synchronization
    221  * can only be safe if the only activity that can happen
    222  * to the list entry is list_del_init(). Eg. it cannot be used
    223  * if another CPU could re-list_add() it.
    224  */
    225 static inline int list_empty_careful(const struct list_head *head)
    226 {
    227 	struct list_head *next = head->next;
    228 	return (next == head) && (next == head->prev);
    229 }
    230 
    231 /**
    232  * list_is_singular - tests whether a list has just one entry.
    233  * @head: the list to test.
    234  */
    235 static inline int list_is_singular(const struct list_head *head)
    236 {
    237 	return !list_empty(head) && (head->next == head->prev);
    238 }
    239 
    240 static inline void __list_cut_position(struct list_head *list,
    241 				       struct list_head *head,
    242 				       struct list_head *entry)
    243 {
    244 	struct list_head *new_first = entry->next;
    245 	list->next = head->next;
    246 	list->next->prev = list;
    247 	list->prev = entry;
    248 	entry->next = list;
    249 	head->next = new_first;
    250 	new_first->prev = head;
    251 }
    252 
    253 /**
    254  * list_cut_position - cut a list into two
    255  * @list: a new list to add all removed entries
    256  * @head: a list with entries
    257  * @entry: an entry within head, could be the head itself
    258  *	and if so we won't cut the list
    259  *
    260  * This helper moves the initial part of @head, up to and
    261  * including @entry, from @head to @list. You should
    262  * pass on @entry an element you know is on @head. @list
    263  * should be an empty list or a list you do not care about
    264  * losing its data.
    265  *
    266  */
    267 static inline void list_cut_position(struct list_head *list,
    268 				     struct list_head *head,
    269 				     struct list_head *entry)
    270 {
    271 	if (list_empty(head))
    272 		return;
    273 	if (list_is_singular(head) && (head->next != entry && head != entry))
    274 		return;
    275 	if (entry == head)
    276 		INIT_LIST_HEAD(list);
    277 	else
    278 		__list_cut_position(list, head, entry);
    279 }
    280 
    281 static inline void __list_splice(const struct list_head *list,
    282 				 struct list_head *prev, struct list_head *next)
    283 {
    284 	struct list_head *first = list->next;
    285 	struct list_head *last = list->prev;
    286 
    287 	first->prev = prev;
    288 	prev->next = first;
    289 
    290 	last->next = next;
    291 	next->prev = last;
    292 }
    293 
    294 /**
    295  * list_splice - join two lists, this is designed for stacks
    296  * @list: the new list to add.
    297  * @head: the place to add it in the first list.
    298  */
    299 static inline void list_splice(const struct list_head *list,
    300 			       struct list_head *head)
    301 {
    302 	if (!list_empty(list))
    303 		__list_splice(list, head, head->next);
    304 }
    305 
    306 /**
    307  * list_splice_tail - join two lists, each list being a queue
    308  * @list: the new list to add.
    309  * @head: the place to add it in the first list.
    310  */
    311 static inline void list_splice_tail(struct list_head *list,
    312 				    struct list_head *head)
    313 {
    314 	if (!list_empty(list))
    315 		__list_splice(list, head->prev, head);
    316 }
    317 
    318 /**
    319  * list_splice_init - join two lists and reinitialise the emptied list.
    320  * @list: the new list to add.
    321  * @head: the place to add it in the first list.
    322  *
    323  * The list at @list is reinitialised
    324  */
    325 static inline void list_splice_init(struct list_head *list,
    326 				    struct list_head *head)
    327 {
    328 	if (!list_empty(list)) {
    329 		__list_splice(list, head, head->next);
    330 		INIT_LIST_HEAD(list);
    331 	}
    332 }
    333 
    334 /**
    335  * list_splice_tail_init - join two lists and reinitialise the emptied list
    336  * @list: the new list to add.
    337  * @head: the place to add it in the first list.
    338  *
    339  * Each of the lists is a queue.
    340  * The list at @list is reinitialised
    341  */
    342 static inline void list_splice_tail_init(struct list_head *list,
    343 					 struct list_head *head)
    344 {
    345 	if (!list_empty(list)) {
    346 		__list_splice(list, head->prev, head);
    347 		INIT_LIST_HEAD(list);
    348 	}
    349 }
    350 
    351 /**
    352  * list_entry - get the struct for this entry
    353  * @ptr:	the &struct list_head pointer.
    354  * @type:	the type of the struct this is embedded in.
    355  * @member:	the name of the list_head within the struct.
    356  */
    357 #define list_entry(ptr, type, member) \
    358 	container_of(ptr, type, member)
    359 
    360 /**
    361  * list_first_entry - get the first element from a list
    362  * @ptr:	the list head to take the element from.
    363  * @type:	the type of the struct this is embedded in.
    364  * @member:	the name of the list_head within the struct.
    365  *
    366  * Note, that list is expected to be not empty.
    367  */
    368 #define list_first_entry(ptr, type, member) \
    369 	list_entry((ptr)->next, type, member)
    370 
    371 /**
    372  * list_for_each	-	iterate over a list
    373  * @pos:	the &struct list_head to use as a loop cursor.
    374  * @head:	the head for your list.
    375  */
    376 #define list_for_each(pos, head) \
    377 	for (pos = (head)->next; prefetch(pos->next), pos != (head); \
    378 		pos = pos->next)
    379 
    380 /**
    381  * list_for_each_prev	-	iterate over a list backwards
    382  * @pos:	the &struct list_head to use as a loop cursor.
    383  * @head:	the head for your list.
    384  */
    385 #define list_for_each_prev(pos, head) \
    386 	for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
    387 		pos = pos->prev)
    388 
    389 /**
    390  * list_for_each_safe - iterate over a list safe against removal of list entry
    391  * @pos:	the &struct list_head to use as a loop cursor.
    392  * @n:		another &struct list_head to use as temporary storage
    393  * @head:	the head for your list.
    394  */
    395 #define list_for_each_safe(pos, n, head) \
    396 	for (pos = (head)->next, n = pos->next; pos != (head); \
    397 		pos = n, n = pos->next)
    398 
    399 /**
    400  * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
    401  * @pos:	the &struct list_head to use as a loop cursor.
    402  * @n:		another &struct list_head to use as temporary storage
    403  * @head:	the head for your list.
    404  */
    405 #define list_for_each_prev_safe(pos, n, head) \
    406 	for (pos = (head)->prev, n = pos->prev; \
    407 	     prefetch(pos->prev), pos != (head); \
    408 	     pos = n, n = pos->prev)
    409 
    410 /**
    411  * list_for_each_entry	-	iterate over list of given type
    412  * @pos:	the type * to use as a loop cursor.
    413  * @head:	the head for your list.
    414  * @member:	the name of the list_head within the struct.
    415  */
    416 #define list_for_each_entry(pos, head, member)				\
    417 	for (pos = list_entry((head)->next, typeof(*pos), member);	\
    418 	     &pos->member != (head); 	\
    419 	     pos = list_entry(pos->member.next, typeof(*pos), member))
    420 
    421 /**
    422  * list_for_each_entry_reverse - iterate backwards over list of given type.
    423  * @pos:	the type * to use as a loop cursor.
    424  * @head:	the head for your list.
    425  * @member:	the name of the list_head within the struct.
    426  */
    427 #define list_for_each_entry_reverse(pos, head, member)			\
    428 	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
    429 	     prefetch(pos->member.prev), &pos->member != (head); 	\
    430 	     pos = list_entry(pos->member.prev, typeof(*pos), member))
    431 
    432 /**
    433  * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
    434  * @pos:	the type * to use as a start point
    435  * @head:	the head of the list
    436  * @member:	the name of the list_head within the struct.
    437  *
    438  * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
    439  */
    440 #define list_prepare_entry(pos, head, member) \
    441 	((pos) ? : list_entry(head, typeof(*pos), member))
    442 
    443 /**
    444  * list_for_each_entry_continue - continue iteration over list of given type
    445  * @pos:	the type * to use as a loop cursor.
    446  * @head:	the head for your list.
    447  * @member:	the name of the list_head within the struct.
    448  *
    449  * Continue to iterate over list of given type, continuing after
    450  * the current position.
    451  */
    452 #define list_for_each_entry_continue(pos, head, member) 		\
    453 	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
    454 	     prefetch(pos->member.next), &pos->member != (head);	\
    455 	     pos = list_entry(pos->member.next, typeof(*pos), member))
    456 
    457 /**
    458  * list_for_each_entry_continue_reverse - iterate backwards from the given point
    459  * @pos:	the type * to use as a loop cursor.
    460  * @head:	the head for your list.
    461  * @member:	the name of the list_head within the struct.
    462  *
    463  * Start to iterate over list of given type backwards, continuing after
    464  * the current position.
    465  */
    466 #define list_for_each_entry_continue_reverse(pos, head, member)		\
    467 	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
    468 	     prefetch(pos->member.prev), &pos->member != (head);	\
    469 	     pos = list_entry(pos->member.prev, typeof(*pos), member))
    470 
    471 /**
    472  * list_for_each_entry_from - iterate over list of given type from the current point
    473  * @pos:	the type * to use as a loop cursor.
    474  * @head:	the head for your list.
    475  * @member:	the name of the list_head within the struct.
    476  *
    477  * Iterate over list of given type, continuing from current position.
    478  */
    479 #define list_for_each_entry_from(pos, head, member) 			\
    480 	for (; prefetch(pos->member.next), &pos->member != (head);	\
    481 	     pos = list_entry(pos->member.next, typeof(*pos), member))
    482 
    483 /**
    484  * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
    485  * @pos:	the type * to use as a loop cursor.
    486  * @n:		another type * to use as temporary storage
    487  * @head:	the head for your list.
    488  * @member:	the name of the list_head within the struct.
    489  */
    490 #define list_for_each_entry_safe(pos, n, head, member)			\
    491 	for (pos = list_entry((head)->next, typeof(*pos), member),	\
    492 		n = list_entry(pos->member.next, typeof(*pos), member);	\
    493 	     &pos->member != (head); 					\
    494 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
    495 
    496 /**
    497  * list_for_each_entry_safe_continue
    498  * @pos:	the type * to use as a loop cursor.
    499  * @n:		another type * to use as temporary storage
    500  * @head:	the head for your list.
    501  * @member:	the name of the list_head within the struct.
    502  *
    503  * Iterate over list of given type, continuing after current point,
    504  * safe against removal of list entry.
    505  */
    506 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
    507 	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
    508 		n = list_entry(pos->member.next, typeof(*pos), member);		\
    509 	     &pos->member != (head);						\
    510 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
    511 
    512 /**
    513  * list_for_each_entry_safe_from
    514  * @pos:	the type * to use as a loop cursor.
    515  * @n:		another type * to use as temporary storage
    516  * @head:	the head for your list.
    517  * @member:	the name of the list_head within the struct.
    518  *
    519  * Iterate over list of given type from current point, safe against
    520  * removal of list entry.
    521  */
    522 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
    523 	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
    524 	     &pos->member != (head);						\
    525 	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
    526 
    527 /**
    528  * list_for_each_entry_safe_reverse
    529  * @pos:	the type * to use as a loop cursor.
    530  * @n:		another type * to use as temporary storage
    531  * @head:	the head for your list.
    532  * @member:	the name of the list_head within the struct.
    533  *
    534  * Iterate backwards over list of given type, safe against removal
    535  * of list entry.
    536  */
    537 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
    538 	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
    539 		n = list_entry(pos->member.prev, typeof(*pos), member);	\
    540 	     &pos->member != (head); 					\
    541 	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
    542 
    543 struct offset {
    544 	struct list_head list;
    545 	unsigned offset;
    546 };
    547 
    548 struct table {
    549 	struct list_head offsets;
    550 	unsigned offset_max;
    551 	unsigned nentry;
    552 	unsigned *table;
    553 	char *gpu_prefix;
    554 };
    555 
    556 static struct offset *offset_new(unsigned o)
    557 {
    558 	struct offset *offset;
    559 
    560 	offset = (struct offset *)malloc(sizeof(struct offset));
    561 	if (offset) {
    562 		INIT_LIST_HEAD(&offset->list);
    563 		offset->offset = o;
    564 	}
    565 	return offset;
    566 }
    567 
    568 static void table_offset_add(struct table *t, struct offset *offset)
    569 {
    570 	list_add_tail(&offset->list, &t->offsets);
    571 }
    572 
    573 static void table_init(struct table *t)
    574 {
    575 	INIT_LIST_HEAD(&t->offsets);
    576 	t->offset_max = 0;
    577 	t->nentry = 0;
    578 	t->table = NULL;
    579 }
    580 
    581 static void table_print(struct table *t)
    582 {
    583 	unsigned nlloop, i, j, n, c, id;
    584 
    585 	nlloop = (t->nentry + 3) / 4;
    586 	c = t->nentry;
    587 	printf("static const unsigned %s_reg_safe_bm[%d] = {\n", t->gpu_prefix,
    588 	       t->nentry);
    589 	for (i = 0, id = 0; i < nlloop; i++) {
    590 		n = 4;
    591 		if (n > c)
    592 			n = c;
    593 		c -= n;
    594 		for (j = 0; j < n; j++) {
    595 			if (j == 0)
    596 				printf("\t");
    597 			else
    598 				printf(" ");
    599 			printf("0x%08X,", t->table[id++]);
    600 		}
    601 		printf("\n");
    602 	}
    603 	printf("};\n");
    604 }
    605 
    606 static int table_build(struct table *t)
    607 {
    608 	struct offset *offset;
    609 	unsigned i, m;
    610 
    611 	t->nentry = ((t->offset_max >> 2) + 31) / 32;
    612 	t->table = (unsigned *)malloc(sizeof(unsigned) * t->nentry);
    613 	if (t->table == NULL)
    614 		return -1;
    615 	memset(t->table, 0xff, sizeof(unsigned) * t->nentry);
    616 	list_for_each_entry(offset, &t->offsets, list) {
    617 		i = (offset->offset >> 2) / 32;
    618 		m = (offset->offset >> 2) & 31;
    619 		m = 1 << m;
    620 		t->table[i] ^= m;
    621 	}
    622 	return 0;
    623 }
    624 
    625 static char gpu_name[10];
    626 static int parser_auth(struct table *t, const char *filename)
    627 {
    628 	FILE *file;
    629 	regex_t mask_rex;
    630 	regmatch_t match[4];
    631 	char buf[1024];
    632 	size_t end;
    633 	int len;
    634 	int done = 0;
    635 	int r;
    636 	unsigned o;
    637 	struct offset *offset;
    638 	char last_reg_s[10];
    639 	int last_reg;
    640 
    641 	if (regcomp
    642 	    (&mask_rex, "(0x[0-9a-fA-F]*) *([_a-zA-Z0-9]*)", REG_EXTENDED)) {
    643 		fprintf(stderr, "Failed to compile regular expression\n");
    644 		return -1;
    645 	}
    646 	file = fopen(filename, "r");
    647 	if (file == NULL) {
    648 		fprintf(stderr, "Failed to open: %s\n", filename);
    649 		return -1;
    650 	}
    651 	fseek(file, 0, SEEK_END);
    652 	end = ftell(file);
    653 	fseek(file, 0, SEEK_SET);
    654 
    655 	/* get header */
    656 	if (fgets(buf, 1024, file) == NULL) {
    657 		fclose(file);
    658 		return -1;
    659 	}
    660 
    661 	/* first line will contain the last register
    662 	 * and gpu name */
    663 	sscanf(buf, "%9s %9s", gpu_name, last_reg_s);
    664 	t->gpu_prefix = gpu_name;
    665 	last_reg = strtol(last_reg_s, NULL, 16);
    666 
    667 	do {
    668 		if (fgets(buf, 1024, file) == NULL) {
    669 			fclose(file);
    670 			return -1;
    671 		}
    672 		len = strlen(buf);
    673 		if (ftell(file) == end)
    674 			done = 1;
    675 		if (len) {
    676 			r = regexec(&mask_rex, buf, 4, match, 0);
    677 			if (r == REG_NOMATCH) {
    678 			} else if (r) {
    679 				fprintf(stderr,
    680 					"Error matching regular expression %d in %s\n",
    681 					r, filename);
    682 				fclose(file);
    683 				return -1;
    684 			} else {
    685 				buf[match[0].rm_eo] = 0;
    686 				buf[match[1].rm_eo] = 0;
    687 				buf[match[2].rm_eo] = 0;
    688 				o = strtol(&buf[match[1].rm_so], NULL, 16);
    689 				offset = offset_new(o);
    690 				table_offset_add(t, offset);
    691 				if (o > t->offset_max)
    692 					t->offset_max = o;
    693 			}
    694 		}
    695 	} while (!done);
    696 	fclose(file);
    697 	if (t->offset_max < last_reg)
    698 		t->offset_max = last_reg;
    699 	return table_build(t);
    700 }
    701 
    702 int main(int argc, char *argv[])
    703 {
    704 	struct table t;
    705 
    706 	if (argc != 2) {
    707 		fprintf(stderr, "Usage: %s <authfile>\n", argv[0]);
    708 		exit(1);
    709 	}
    710 	table_init(&t);
    711 	if (parser_auth(&t, argv[1])) {
    712 		fprintf(stderr, "Failed to parse file %s\n", argv[1]);
    713 		return -1;
    714 	}
    715 	table_print(&t);
    716 	return 0;
    717 }
    718