rpm  5.2.1
rpmte.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmio.h>
8 #include <rpmiotypes.h> /* XXX fnpyKey */
9 
10 #include <rpmtypes.h>
11 #include <rpmtag.h>
12 
13 #include "rpmds.h"
14 #include "rpmfi.h"
15 
16 #define _RPMTE_INTERNAL
17 #include "rpmte.h"
18 #include "rpmts.h"
19 
20 #include "debug.h"
21 
22 /*@unchecked@*/
23 int _rpmte_debug = 0;
24 
25 /*@access alKey @*/
26 /*@access rpmts @*/ /* XXX cast */
27 /*@access rpmtsi @*/
28 
30 {
31  te->PRCO = rpmdsFreePRCO(te->PRCO);
32 }
33 
38 static void delTE(rpmte p)
39  /*@globals fileSystem @*/
40  /*@modifies p, fileSystem @*/
41 {
42  p->relocs = rpmfiFreeRelocations(p->relocs);
43 
44  rpmteCleanDS(p);
45 
46  p->fi = rpmfiFree(p->fi);
47 
48 /*@-refcounttrans@*/ /* FIX: XfdFree annotation */
49  if (p->fd != NULL)
50  p->fd = fdFree(p->fd, "delTE");
51 /*@=refcounttrans@*/
52 
53  p->os = _free(p->os);
54  p->arch = _free(p->arch);
55  p->epoch = _free(p->epoch);
56  p->name = _free(p->name);
57  p->version = _free(p->version);
58  p->release = _free(p->release);
59 #ifdef RPM_VENDOR_MANDRIVA
60  p->distepoch = _free(p->distepoch);
61 #endif
62  p->NEVR = _free(p->NEVR);
63  p->NEVRA = _free(p->NEVRA);
64  p->pkgid = _free(p->pkgid);
65  p->hdrid = _free(p->hdrid);
66  p->sourcerpm = _free(p->sourcerpm);
67 
68  p->replaced = _free(p->replaced);
69 
70  p->flink.NEVRA = argvFree(p->flink.NEVRA);
71  p->flink.Pkgid = argvFree(p->flink.Pkgid);
72  p->flink.Hdrid = argvFree(p->flink.Hdrid);
73  p->blink.NEVRA = argvFree(p->blink.NEVRA);
74  p->blink.Pkgid = argvFree(p->blink.Pkgid);
75  p->blink.Hdrid = argvFree(p->blink.Hdrid);
76 
77  (void)headerFree(p->h);
78  p->h = NULL;
79 
80  /*@-nullstate@*/ /* FIX: p->{NEVR,name} annotations */
81  return;
82  /*@=nullstate@*/
83 }
84 
93 static void addTE(rpmts ts, rpmte p, Header h,
94  /*@dependent@*/ /*@null@*/ fnpyKey key,
95  /*@null@*/ rpmRelocation relocs)
96  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
97  /*@modifies ts, p, h,
98  rpmGlobalMacroContext, fileSystem, internalState @*/
99 {
100  int scareMem = 0;
101  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
102  int xx;
103 
104  he->tag = RPMTAG_NVRA;
105  xx = headerGet(h, he, 0);
106 assert(he->p.str != NULL);
107  p->NEVR = (xx ? he->p.str : xstrdup("?N-?V-?R.?A"));
108 
109  he->tag = RPMTAG_NAME;
110  xx = headerGet(h, he, 0);
111  p->name = (xx ? he->p.str : xstrdup("?RPMTAG_NAME?"));
112  he->tag = RPMTAG_VERSION;
113  xx = headerGet(h, he, 0);
114  p->version = (char *)(xx ? he->p.str : xstrdup("?RPMTAG_VERSION?"));
115  he->tag = RPMTAG_RELEASE;
116  xx = headerGet(h, he, 0);
117  p->release = (char *)(xx ? he->p.str : xstrdup("?RPMTAG_RELEASE?"));
118 
119  p->db_instance = 0;
120 
121  he->tag = RPMTAG_PKGID;
122  xx = headerGet(h, he, 0);
123  if (he->p.ui8p != NULL) {
124  static const char hex[] = "0123456789abcdef";
125  char * t;
126  rpmuint32_t i;
127 
128  p->pkgid = t = xmalloc((2*he->c) + 1);
129  for (i = 0 ; i < he->c; i++) {
130  *t++ = hex[ (unsigned)((he->p.ui8p[i] >> 4) & 0x0f) ];
131  *t++ = hex[ (unsigned)((he->p.ui8p[i] ) & 0x0f) ];
132  }
133  *t = '\0';
134  he->p.ptr = _free(he->p.ptr);
135  } else
136  p->pkgid = NULL;
137 
138  he->tag = RPMTAG_HDRID;
139  xx = headerGet(h, he, 0);
140  p->hdrid = (xx ? he->p.str : xstrdup("?RPMTAG_HDRID?"));
141 
142  he->tag = RPMTAG_SOURCERPM;
143  xx = headerGet(h, he, 0);
144  p->sourcerpm = (xx ? he->p.str : NULL);
145 
146  he->tag = RPMTAG_ARCH;
147  xx = headerGet(h, he, 0);
148  p->arch = (xx ? he->p.str : xstrdup("?RPMTAG_ARCH?"));
149 
150  he->tag = RPMTAG_OS;
151  xx = headerGet(h, he, 0);
152  p->os = (xx ? he->p.str : xstrdup("?RPMTAG_OS?"));
153 
154  p->isSource =
155  (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
156  headerIsEntry(h, RPMTAG_ARCH) != 0);
157 
158  p->NEVRA = xstrdup(p->NEVR);
159 
160  he->tag = RPMTAG_EPOCH;
161  xx = headerGet(h, he, 0);
162  if (he->p.ui32p != NULL) {
163  p->epoch = xmalloc(20);
164  sprintf(p->epoch, "%u", he->p.ui32p[0]);
165  he->p.ptr = _free(he->p.ptr);
166  } else
167  p->epoch = NULL;
168 
169 #ifdef RPM_VENDOR_MANDRIVA
170  he->tag = RPMTAG_DISTEPOCH;
171  xx = headerGet(h, he, 0);
172  if (he->p.str != NULL) {
173  p->distepoch = (char*)(xx ? he->p.str : xstrdup("?RPMTAG_DISTEPOCH?"));
174  } else
175  p->distepoch = NULL;
176 #endif
177 
178  p->installed = 0;
179 
180  p->relocs = rpmfiDupeRelocations(relocs, &p->nrelocs);
181  p->autorelocatex = -1;
182 
183  p->key = key;
184  p->fd = NULL;
185 
186  p->replaced = NULL;
187 
188  p->pkgFileSize = 0;
189  memset(p->originTid, 0, sizeof(p->originTid));
190  memset(p->originTime, 0, sizeof(p->originTime));
191 
192  p->PRCO = rpmdsNewPRCO(h);
193 
194  { rpmte savep = rpmtsSetRelocateElement(ts, p);
195  p->fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
196  (void) rpmtsSetRelocateElement(ts, savep);
197  }
198 
201 /*@-compdef@*/
202  return;
203 /*@=compdef@*/
204 }
205 
206 static void rpmteFini(void * _te)
207  /*@modifies _te @*/
208 {
209  rpmte te = _te;
210 
211  delTE(te);
212 }
213 
214 /*@unchecked@*/ /*@only@*/ /*@null@*/
216 
217 static rpmte rpmteGetPool(/*@null@*/ rpmioPool pool)
218  /*@globals _rpmtePool, fileSystem, internalState @*/
219  /*@modifies pool, _rpmtePool, fileSystem, internalState @*/
220 {
221  rpmte te;
222 
223  if (_rpmtePool == NULL) {
224  _rpmtePool = rpmioNewPool("te", sizeof(*te), -1, _rpmte_debug,
225  NULL, NULL, rpmteFini);
226  pool = _rpmtePool;
227  }
228  return (rpmte) rpmioGetPool(pool, sizeof(*te));
229 }
230 
232  rpmElementType type,
233  fnpyKey key,
234  rpmRelocation relocs,
235  int dboffset,
236  alKey pkgKey)
237 {
238  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
239  rpmte p = rpmteGetPool(_rpmtePool);
240  int xx;
241 
242  p->type = type;
243 
244  addTE(ts, p, h, key, relocs);
245  switch (type) {
246  case TR_ADDED:
247  p->u.addedKey = pkgKey;
248  /* XXX 256 is only an estimate of signature header. */
249  p->pkgFileSize = 96 + 256;
250  he->tag = RPMTAG_SIGSIZE;
251  xx = headerGet(h, he, 0);
252  if (xx && he->p.ui32p)
253  p->pkgFileSize += *he->p.ui32p;
254  he->p.ptr = _free(he->p.ptr);
255  break;
256  case TR_REMOVED:
257  p->u.addedKey = pkgKey;
258  p->u.removed.dboffset = dboffset;
259  break;
260  }
261  return p;
262 }
263 
264 /* Get the DB Instance value */
265 unsigned int rpmteDBInstance(rpmte te)
266 {
267  return (te != NULL ? te->db_instance : 0);
268 }
269 
270 /* Set the DB Instance value */
271 void rpmteSetDBInstance(rpmte te, unsigned int instance)
272 {
273  if (te != NULL)
274  te->db_instance = instance;
275 }
276 
278 {
279 /*@-castexpose -retalias -retexpose @*/
280  return (te != NULL && te->h != NULL ? headerLink(te->h) : NULL);
281 /*@=castexpose =retalias =retexpose @*/
282 }
283 
285 {
286  if (te != NULL) {
287  (void)headerFree(te->h);
288  te->h = NULL;
289 /*@-assignexpose -castexpose @*/
290  if (h != NULL)
291  te->h = headerLink(h);
292 /*@=assignexpose =castexpose @*/
293  }
294  return NULL;
295 }
296 
298 {
299  return (te != NULL ? te->type : (rpmElementType)-1);
300 }
301 
302 const char * rpmteN(rpmte te)
303 {
304  return (te != NULL ? te->name : NULL);
305 }
306 
307 const char * rpmteE(rpmte te)
308 {
309  return (te != NULL ? te->epoch : NULL);
310 }
311 
312 const char * rpmteV(rpmte te)
313 {
314  return (te != NULL ? te->version : NULL);
315 }
316 
317 const char * rpmteR(rpmte te)
318 {
319  return (te != NULL ? te->release : NULL);
320 }
321 
322 #ifdef RPM_VENDOR_MANDRIVA
323 const char * rpmteD(rpmte te)
324 {
325  return (te != NULL ? te->distepoch : NULL);
326 }
327 #endif
328 
329 const char * rpmteA(rpmte te)
330 {
331  return (te != NULL ? te->arch : NULL);
332 }
333 
334 const char * rpmteO(rpmte te)
335 {
336  return (te != NULL ? te->os : NULL);
337 }
338 
340 {
341  return (te != NULL ? te->isSource : 0);
342 }
343 
345 {
346  return (te != NULL ? te->color : 0);
347 }
348 
350 {
351  int ocolor = 0;
352  if (te != NULL) {
353  ocolor = te->color;
354  te->color = color;
355  }
356  return ocolor;
357 }
358 
360 {
361  return (te != NULL ? te->pkgFileSize : 0);
362 }
363 
365 {
366  return te->originTid;
367 }
368 
370 {
371  return te->originTime;
372 }
373 
375 {
376  return (te != NULL ? te->depth : 0);
377 }
378 
379 int rpmteSetDepth(rpmte te, int ndepth)
380 {
381  int odepth = 0;
382  if (te != NULL) {
383  odepth = te->depth;
384  te->depth = ndepth;
385  }
386  return odepth;
387 }
388 
390 {
391  return (te != NULL ? te->depth : 0);
392 }
393 
394 int rpmteSetBreadth(rpmte te, int nbreadth)
395 {
396  int obreadth = 0;
397  if (te != NULL) {
398  obreadth = te->breadth;
399  te->breadth = nbreadth;
400  }
401  return obreadth;
402 }
403 
405 {
406  return (te != NULL ? te->npreds : 0);
407 }
408 
409 int rpmteSetNpreds(rpmte te, int npreds)
410 {
411  int opreds = 0;
412  if (te != NULL) {
413  opreds = te->npreds;
414  te->npreds = npreds;
415  }
416  return opreds;
417 }
418 
420 {
421  return (te != NULL ? te->tree : 0);
422 }
423 
424 int rpmteSetTree(rpmte te, int ntree)
425 {
426  int otree = 0;
427  if (te != NULL) {
428  otree = te->tree;
429  te->tree = ntree;
430  }
431  return otree;
432 }
433 
435 {
436  return (te != NULL ? te->parent : NULL);
437 }
438 
440 {
441  rpmte opte = NULL;
442  if (te != NULL) {
443  opte = te->parent;
444  /*@-assignexpose -temptrans@*/
445  te->parent = pte;
446  /*@=assignexpose =temptrans@*/
447  }
448  return opte;
449 }
450 
452 {
453  return (te != NULL ? te->degree : 0);
454 }
455 
456 int rpmteSetDegree(rpmte te, int ndegree)
457 {
458  int odegree = 0;
459  if (te != NULL) {
460  odegree = te->degree;
461  te->degree = ndegree;
462  }
463  return odegree;
464 }
465 
467 {
468  /*@-compdef -retalias -retexpose -usereleased @*/
469  return te->tsi;
470  /*@=compdef =retalias =retexpose =usereleased @*/
471 }
472 
474 {
475  if (te != NULL && rpmteTSI(te) != NULL) {
476  tsortInfo tsi;
477 
478  /* Clean up tsort remnants (if any). */
479  while ((tsi = rpmteTSI(te)->tsi_next) != NULL) {
480  rpmteTSI(te)->tsi_next = tsi->tsi_next;
481  tsi->tsi_next = NULL;
482  tsi = _free(tsi);
483  }
484  te->tsi = _free(te->tsi);
485  }
486  /*@-nullstate@*/ /* FIX: te->tsi is NULL */
487  return;
488  /*@=nullstate@*/
489 }
490 
492 {
493  if (te != NULL) {
494  rpmteFreeTSI(te);
495  te->tsi = xcalloc(1, sizeof(*te->tsi));
496  }
497 }
498 
500 {
501  return (te != NULL ? te->u.addedKey : RPMAL_NOMATCH);
502 }
503 
505 {
506  alKey opkgKey = RPMAL_NOMATCH;
507  if (te != NULL) {
508  opkgKey = te->u.addedKey;
509  te->u.addedKey = npkgKey;
510  }
511  return opkgKey;
512 }
513 
514 
516 {
517  return (te != NULL ? te->u.removed.dboffset : 0);
518 }
519 
520 const char * rpmteNEVR(rpmte te)
521 {
522  return (te != NULL ? te->NEVR : NULL);
523 }
524 
525 const char * rpmteNEVRA(rpmte te)
526 {
527  return (te != NULL ? te->NEVRA : NULL);
528 }
529 
530 const char * rpmtePkgid(rpmte te)
531 {
532  return (te != NULL ? te->pkgid : NULL);
533 }
534 
535 const char * rpmteHdrid(rpmte te)
536 {
537  return (te != NULL ? te->hdrid : NULL);
538 }
539 
540 const char * rpmteSourcerpm(rpmte te)
541 {
542  return (te != NULL ? te->sourcerpm : NULL);
543 }
544 
546 {
547  /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
548  return (te != NULL ? te->fd : NULL);
549  /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
550 }
551 
553 {
554  return (te != NULL ? te->key : NULL);
555 }
556 
558 {
559  return (te != NULL ? rpmdsFromPRCO(te->PRCO, tag) : NULL);
560 }
561 
563 {
564  /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/
565  if (te == NULL)
566  return NULL;
567 
568  if (tag == RPMTAG_BASENAMES)
569  return te->fi;
570  else
571  return NULL;
572  /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/
573 }
574 
575 void rpmteColorDS(rpmte te, rpmTag tag)
576 {
577  rpmfi fi = rpmteFI(te, RPMTAG_BASENAMES);
578  rpmds ds = rpmteDS(te, tag);
579  char deptype = 'R';
580  char mydt;
581  const rpmuint32_t * ddict;
582  rpmuint32_t * colors;
583  rpmuint32_t * refs;
584  rpmuint32_t val;
585  int Count;
586  size_t nb;
587  unsigned ix;
588  int ndx, i;
589 
590  if (!(te && (Count = rpmdsCount(ds)) > 0 && rpmfiFC(fi) > 0))
591  return;
592 
593  switch (tag) {
594  default:
595  return;
596  /*@notreached@*/ break;
597  case RPMTAG_PROVIDENAME:
598  deptype = 'P';
599  break;
600  case RPMTAG_REQUIRENAME:
601  deptype = 'R';
602  break;
603  }
604 
605  nb = Count * sizeof(*colors);
606  colors = memset(alloca(nb), 0, nb);
607  nb = Count * sizeof(*refs);
608  refs = memset(alloca(nb), -1, nb);
609 
610  /* Calculate dependency color and reference count. */
611  fi = rpmfiInit(fi, 0);
612  if (fi != NULL)
613  while (rpmfiNext(fi) >= 0) {
614  val = rpmfiFColor(fi);
615  ddict = NULL;
616  ndx = rpmfiFDepends(fi, &ddict);
617  if (ddict != NULL)
618  while (ndx-- > 0) {
619  ix = *ddict++;
620  mydt = (char)((ix >> 24) & 0xff);
621  if (mydt != deptype)
622  /*@innercontinue@*/ continue;
623  ix &= 0x00ffffff;
624 assert ((int)ix < Count);
625  colors[ix] |= val;
626  refs[ix]++;
627  }
628  }
629 
630  /* Set color/refs values in dependency set. */
631  ds = rpmdsInit(ds);
632  while ((i = rpmdsNext(ds)) >= 0) {
633  val = colors[i];
634  te->color |= val;
635  (void) rpmdsSetColor(ds, val);
636  val = refs[i];
637  (void) rpmdsSetRefs(ds, val);
638  }
639 }
640 
641 /*@unchecked@*/
642 static int __mydebug = 0;
643 
644 int rpmteChain(rpmte p, rpmte q, Header oh, const char * msg)
645 {
646  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
647  const char * blinkNEVRA = NULL;
648  const char * blinkPkgid = NULL;
649  const char * blinkHdrid = NULL;
650  int xx;
651 
652  if (msg == NULL)
653  msg = "";
654  he->tag = RPMTAG_NVRA;
655  xx = headerGet(oh, he, 0);
656 assert(he->p.str != NULL);
657  blinkNEVRA = he->p.str;
658 
659  /*
660  * Convert binary pkgid to a string.
661  * XXX Yum's borken conception of a "header" doesn't have signature
662  * tags appended.
663  */
664  he->tag = RPMTAG_PKGID;
665  xx = headerGet(oh, he, 0);
666  if (xx && he->p.ui8p != NULL) {
667  static const char hex[] = "0123456789abcdef";
668  char * t;
669  rpmuint32_t i;
670 
671  blinkPkgid = t = xmalloc((2*he->c) + 1);
672  for (i = 0 ; i < he->c; i++) {
673  *t++ = hex[ ((he->p.ui8p[i] >> 4) & 0x0f) ];
674  *t++ = hex[ ((he->p.ui8p[i] ) & 0x0f) ];
675  }
676  *t = '\0';
677  he->p.ptr = _free(he->p.ptr);
678  } else
679  blinkPkgid = NULL;
680 
681  he->tag = RPMTAG_HDRID;
682  xx = headerGet(oh, he, 0);
683  blinkHdrid = he->p.str;
684 
685 /*@-modfilesys@*/
686 if (__mydebug)
687 fprintf(stderr, "%s argvAdd(&q->flink.NEVRA, \"%s\")\n", msg, p->NEVRA);
688  xx = argvAdd(&q->flink.NEVRA, p->NEVRA);
689 if (__mydebug)
690 fprintf(stderr, "%s argvAdd(&p->blink.NEVRA, \"%s\")\n", msg, blinkNEVRA);
691  xx = argvAdd(&p->blink.NEVRA, blinkNEVRA);
692 if (__mydebug)
693 fprintf(stderr, "%s argvAdd(&q->flink.Pkgid, \"%s\")\n", msg, p->pkgid);
694  if (p->pkgid != NULL)
695  xx = argvAdd(&q->flink.Pkgid, p->pkgid);
696 if (__mydebug)
697 fprintf(stderr, "%s argvAdd(&p->blink.Pkgid, \"%s\")\n", msg, blinkPkgid);
698  if (blinkPkgid != NULL)
699  xx = argvAdd(&p->blink.Pkgid, blinkPkgid);
700 if (__mydebug)
701 fprintf(stderr, "%s argvAdd(&q->flink.Hdrid, \"%s\")\n", msg, p->hdrid);
702  if (p->hdrid != NULL)
703  xx = argvAdd(&q->flink.Hdrid, p->hdrid);
704 if (__mydebug)
705 fprintf(stderr, "%s argvAdd(&p->blink.Hdrid, \"%s\")\n", msg, blinkHdrid);
706  if (blinkHdrid != NULL)
707  xx = argvAdd(&p->blink.Hdrid, blinkHdrid);
708 /*@=modfilesys@*/
709 
710  blinkNEVRA = _free(blinkNEVRA);
711  blinkPkgid = _free(blinkPkgid);
712  blinkHdrid = _free(blinkHdrid);
713 
714  return 0;
715 }
716 
717 int rpmtsiOc(rpmtsi tsi)
718 {
719  return tsi->ocsave;
720 }
721 
722 /*@-mustmod@*/
723 static void rpmtsiFini(void * _tsi)
724  /*@modifies _tsi @*/
725 {
726  rpmtsi tsi = _tsi;
727 /*@-internalglobs@*/
728  (void)rpmtsFree(tsi->ts);
729  tsi->ts = NULL;
730 /*@=internalglobs@*/
731 }
732 /*@=mustmod@*/
733 
734 /*@unchecked@*/ /*@only@*/ /*@null@*/
736 
737 static rpmtsi rpmtsiGetPool(/*@null@*/ rpmioPool pool)
738  /*@globals _rpmtsiPool, fileSystem, internalState @*/
739  /*@modifies pool, _rpmtsiPool, fileSystem, internalState @*/
740 {
741  rpmtsi tsi;
742 
743  if (_rpmtsiPool == NULL) {
744  _rpmtsiPool = rpmioNewPool("tsi", sizeof(*tsi), -1, _rpmte_debug,
745  NULL, NULL, rpmtsiFini);/* XXX _rpmtsi_debug? */
746  pool = _rpmtsiPool;
747  }
748  return (rpmtsi) rpmioGetPool(pool, sizeof(*tsi));
749 }
750 
751 rpmtsi XrpmtsiInit(rpmts ts, const char * fn, unsigned int ln)
752 {
753  rpmtsi tsi = rpmtsiGetPool(_rpmtsiPool);
754 
755 /*@-assignexpose -castexpose @*/
756  tsi->ts = rpmtsLink(ts, "rpmtsi");
757 /*@=assignexpose =castexpose @*/
758  tsi->reverse = 0;
759  tsi->oc = (tsi->reverse ? (rpmtsNElements(ts) - 1) : 0);
760  tsi->ocsave = tsi->oc;
761 
762  return (rpmtsi) rpmioLinkPoolItem((rpmioItem)tsi, "rpmtsiInit", fn, ln);
763 }
764 
770 static /*@null@*/ /*@dependent@*/
772  /*@modifies tsi @*/
773 {
774  rpmte te = NULL;
775  int oc = -1;
776 
777  if (tsi == NULL || tsi->ts == NULL || rpmtsNElements(tsi->ts) <= 0)
778  return te;
779 
780  if (tsi->reverse) {
781  if (tsi->oc >= 0) oc = tsi->oc--;
782  } else {
783  if (tsi->oc < rpmtsNElements(tsi->ts)) oc = tsi->oc++;
784  }
785  tsi->ocsave = oc;
786  if (oc != -1)
787  te = rpmtsElement(tsi->ts, oc);
788  return te;
789 }
790 
792 {
793  rpmte te;
794 
795  while ((te = rpmtsiNextElement(tsi)) != NULL) {
796  if (type == 0 || (te->type & type) != 0)
797  break;
798  }
799  return te;
800 }