void freenode(long t)
{
node nod;

  readnode(t, &nod);
  nod.ptr[0] = freelist;
  freelist = t;
  writenode(t, &nod);
}
void wrstart(void)
{

  start[0] = root;
  start[1] = freelist;
  if (fseek(fptree, 0L, SEEK_SET))
	  error("fseek in wrstart");
  if (fwrite(start, sizeof(long), 2, fptree) == 0)
	  error("fwrite in wrstart");
  if (root != NIL)
	  writenode(root, &rootnode);
}
long getnode(void)
{
long t;
node nod;

  if (freelist == NIL) {
	 if (fseek(fptree, 0L, SEEK_END))
		 error("fseek in getnode");
  t = ftell(fptree);
  writenode(t, &nod);  }         /*  Allocate space on disk  */

  else{
	  t = freelist;
		readnode(t, &nod);             /*  To update freelist      */
		freelist = nod.ptr[0];
 }
 return(t);
}
void writenode(genpt p){
	genpt temp=p;

	if(temp->tag==data){
		printf("%c",temp->u.c);
	}
	printf("(");
	for(temp=temp->link;temp!=NULL;temp=temp->link){
		if(temp->tag==data)
			printf("%c",temp->u.c);
		else{
			genpt temp_list=temp->u.list;
			writenode(temp_list);
		}
		if(temp->link!=NULL)
			printf(",");
	}
	printf(")");
}
/*  Driver function for node insertion, called only in the main function.

	 Most of the work is delegated to 'ins'.
*/
status insert(char *index, long value)
{
long tnew, u;
btuple_t x;
strcpy(x.index,index);
x.value = value;
btuple_t xnew;
status code = ins(x, root, &xnew, &tnew);

  if (code == DUPLICATEKEY)
	 printf("Duplicate uid %s ignored \n", x.index);
  else
	 if (code == INSERTNOTCOMPLETE){
		u = getnode();
		rootnode.cnt = 1;
		rootnode.tuple[0] = xnew;
		rootnode.ptr[0] = root;
		rootnode.ptr[1] = tnew;
		root = u;
		writenode(u, &rootnode);
		code = SUCCESS;
	}
	return(code);     /*  return index: SUCCESS  of DUPLICATEKEY  */
}
void writetree(genpt p){
	genpt temp=p->u.list;
	writenode(temp);
}
/* Delete item x in B-tree with root t.

	Return index:

	  SUCCESS, NOTFOUND, OR UNDERFLOW
*/
status del(btuple_t x, long t)
{
int i, j, *n, *nleft, *nright, borrowleft=0, nq;
 btuple_t *k, *ltuple, *rtuple, *item, *addr;
status code;
long *p, left, right, *lptr, *rptr, q, q1;
node nod, nod1, nod2, nodL, nodR;

 if (t == NIL)
	return(NOTFOUND);
 readnode(t, &nod);
 n = & nod.cnt;
 k = nod.tuple;
 p=nod.ptr;
 i=binsearch(x, k, *n);
 /* *t is a leaf */
 if (p[0] == NIL){
	if (i == *n || strcmp(x.index,k[i].index) < 0)
		 return NOTFOUND;
	 /* x is now equal to k[i], located in a leaf:  */
	 for (j=i+1; j < *n; j++){
		 k[j-1] = k[j];
		 p[j] = p[j+1];
	 }
	 --*n;
	writenode(t, &nod);
	 return(*n >= (t==root ? 1 : M) ? SUCCESS : UNDERFLOW);
  }
  /*  t is an interior node (not a leaf): */
  item = k+i;
  left = p[i];
  readnode(left, &nod1);
  nleft = & nod1.cnt;
    /* x found in interior node.  Go to left child *p[i] and then follow a

	  path all the way to a leaf, using rightmost branches:  */
  if (i < *n && strcmp(x.index,item->index) == 0){
	  q = p[i];
	  readnode(q, &nod1);
	  nq = nod1.cnt;
	  while (q1 = nod1.ptr[nq], q1!= NIL){
			 q = q1;
			 readnode(q, &nod1);
			 nq = nod1.cnt;
	  }
	  /*  Exchange k[i] with the rightmost item in that leaf:   */
	  addr = nod1.tuple + nq -1;
	  *item = *addr;
	  *addr = x;
	  writenode(t, &nod);
	  writenode(q, &nod1);
  }

  /*  Delete x in subtree with root p[i]:  */
	code = del(x, left);
	if (code != UNDERFLOW)
		return code;
	/*  Underflow, borrow, and , if necessary, merge:  */
	if (i < *n)
		readnode(p[i+1], &nodR);
	if (i == *n || nodR.cnt == M){
	  if (i > 0){
		 readnode(p[i-1], &nodL);
		 if (i == *n || nodL.cnt > M)
			borrowleft = 1;
	  }
	}
	/* borrow from left sibling */
	if (borrowleft){
	  item = k+i-1;
		left = p[i-1];
		right = p[i];
		nod1 = nodL;
		readnode(right, &nod2);
		nleft = & nod1.cnt;
	}else{
		right = p[i+1];        /*  borrow from right sibling   */
		readnode(left, &nod1);
		nod2 = nodR;
	}
	nright = & nod2.cnt;
	ltuple = nod1.tuple;
	rtuple = nod2.tuple;
	lptr = nod1.ptr;
	rptr = nod2.ptr;
	if (borrowleft){
		rptr[*nright + 1] = rptr[*nright];
		for (j=*nright; j>0; j--){
			rtuple[j] = rtuple[j-1];
			rptr[j] = rptr[j-1];
		}
		++*nright;
		rtuple[0] = *item;
		rptr[0] = lptr[*nleft];
		*item = ltuple[*nleft - 1];
		if (--*nleft >= M){
		  writenode(t, &nod);
		  writenode(left, &nod1);
		  writenode(right, &nod2);
		  return SUCCESS;
		}
	}else
	/* borrow from right sibling */
	 if (*nright > M){
		 ltuple[M-1] = *item;
		 lptr[M] = rptr[0];
		 *item = rtuple[0];
		 ++*nleft;
		 --*nright;
		 for (j=0; j < *nright; j++){
			 rptr[j] = rptr[j+1];
			 rtuple[j] = rtuple[j+1];
		 }
		 rptr[*nright] = rptr[*nright + 1];
		 writenode(t, &nod);
		 writenode(left, &nod1);
		 writenode(right, &nod2);
		 return(SUCCESS);
	 }
	 /*  Merge   */
	 ltuple[M-1] = *item;
	 lptr[M] = rptr[0];
	 for (j=0; j<M; j++){
		ltuple[M+j] = rtuple[j];
		lptr[M+j+1] = rptr[j+1];
	 }
	 *nleft = MM;
	 freenode(right);
	 for (j=i+1; j < *n; j++){
		 k[j-1] = k[j];
		 p[j] = p[j+1];
	 }
	 --*n;
	 writenode(t, &nod);
	 writenode(left, &nod1);
	 return( *n >= (t==root ? 1 : M) ? SUCCESS : UNDERFLOW);
}
/*
	Insert x in B-tree with root t.  If not completely successful, the
	 integer *y and the pointer *u remain to be inserted.
*/
status ins(btuple_t x, long t, btuple_t *y, long *u)
{
 long tnew, p_final, *p;
 int i, j, *n;
 btuple_t *k;
 btuple_t xnew, k_final;
 status code;
 node nod, newnod;

	/*  Examine whether t is a pointer member in a leaf  */
	if (t == NIL){
		*u = NIL;
		 *y = x;
		 return(INSERTNOTCOMPLETE);
	}
	readnode(t, &nod);
	n = & nod.cnt;
	k = nod.tuple;
	p = nod.ptr;
	/*  Select pointer p[i] and try to insert x in  the subtree of whichp[i]
	  is  the root:  */
	i = binsearch(x, k, *n);
	if (i < *n && strcmp(x.index,k[i].index) == 0)
	  return(DUPLICATEKEY);
	code = ins(x, p[i], &xnew, &tnew);
	if (code != INSERTNOTCOMPLETE)
	  return code;
	/* Insertion in subtree did not completely succeed; try to insert xnew and
	tnew in the current node:  */
	if (*n < MM){
		i = binsearch(xnew, k, *n);
		for (j = *n; j > i; j--){
			k[j] = k[j-1];
			p[j+1] = p[j];
		}
	  k[i] = xnew;
	  p[i+1] = tnew;
	  ++*n;
	  writenode(t, &nod);
	  return(SUCCESS);
	}
	/*  The current node was already full, so split it.  Pass item k[M] in the
	 middle of the augmented sequence back through parameter y, so that it
	 can move upward in the tree.  Also, pass a pointer to the newly created
	 node back through u.  Return INSERTNOTCOMPLETE, to report that insertion
	 was not completed:    */
	if (i == MM){
	  k_final = xnew;
	  p_final = tnew;
	 }else{
		  k_final = k[MM-1];
		  p_final = p[MM];
		  for (j=MM-1; j>i; j--){
			  k[j] = k[j-1];
			  p[j+1] = p[j];
		  }
			k[i] = xnew;
			p[i+1] = tnew;
	}
	*y = k[M];
	*n = M;
	*u = getnode(); newnod.cnt = M;
	for (j=0; j< M-1; j++){
		newnod.tuple[j] = k[j+M+1];
		newnod.ptr[j] = p[j+M+1];
	}
	newnod.ptr[M-1] = p[MM];
	newnod.tuple[M-1] = k_final;
	newnod.ptr[M] = p_final;
	writenode(t, &nod);
	writenode(*u, &newnod);
	return(INSERTNOTCOMPLETE);
}