1 /* namespace.c:
2  *
3  ****************************************************************
4  * Copyright (C) 2003 Tom Lord
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 
11 #include "hackerlab/bugs/panic.h"
12 #include "hackerlab/fmt/cvt.h"
13 #include "hackerlab/char/char-class.h"
14 #include "hackerlab/char/str.h"
15 #include "hackerlab/sort/qsort.h"
16 #include "hackerlab/vu/safe.h"
17 #include "tla/libfsutils/safety.h"
18 #include "tla/libarch/my.h"
19 #include "tla/libarch/namespace.h"
20 
21 
22 /* __STDC__ prototypes for static functions */
23 static const t_uchar * over_opt_archive_prefix (const t_uchar * name);
24 static const t_uchar * over_archive_name (const t_uchar * in);
25 static const t_uchar * over_basename (const t_uchar * in);
26 static const t_uchar * over_separator (const t_uchar * in);
27 static const t_uchar * over_version (const t_uchar * in);
28 static const t_uchar * over_patch_level (const t_uchar * in);
29 
30 
31 
32 int
arch_valid_id(const t_uchar * id)33 arch_valid_id (const t_uchar * id)
34 {
35   const t_uchar * non_empty_marker;
36 
37   /* This isn't exactly the same as larch's version --
38    * it's a superset.   Both are wrong, really. :-)
39    */
40 
41   while (char_is_alnum (*id)
42          || char_is_space (*id)
43          || (char_is_punct (*id) && (*id != '<')))
44     ++id;
45 
46   if (*id != '<')
47     return 0;
48 
49   ++id;
50 
51   non_empty_marker = id;
52 
53   while (char_is_alnum (*id)
54          || (*id == '-')
55          || (*id == '+')
56          || (*id == '_')
57          || (*id == '.'))
58     ++id;
59 
60   if (id == non_empty_marker)
61     return 0;
62 
63   if (*id != '@')
64     return 0;
65 
66   ++id;
67 
68   non_empty_marker = id;
69 
70   while (char_is_alnum (*id)
71          || (*id == '-')
72          || (*id == '_')
73          || (*id == '.'))
74     ++id;
75 
76   if (*id != '>')
77     return 0;
78 
79   ++id;
80 
81   if (*id)
82     return 0;
83 
84   return 1;
85 }
86 
87 int
arch_valid_archive_name(const t_uchar * name)88 arch_valid_archive_name (const t_uchar * name)
89 {
90   const t_uchar * end;
91 
92   if (!name)
93     return 0;
94 
95   end = over_archive_name (name);
96 
97   if (!end || *end)
98     return 0;
99   else
100     return 1;
101 }
102 
103 int
arch_valid_patch_level_name(const t_uchar * name)104 arch_valid_patch_level_name (const t_uchar * name)
105 {
106   t_uchar * lvl;
107 
108   if (!str_cmp (name, "base-0"))
109     return 1;
110 
111   if (str_cmp_prefix ("patch-", name) && str_cmp_prefix ("version-", name) && str_cmp_prefix ("versionfix-", name))
112     return 0;
113 
114   lvl = str_chr_index (name, '-');
115   if (!lvl)
116     return 0;
117 
118   ++lvl;
119 
120   if (!*lvl)
121     return 0;
122 
123   while (char_is_digit (*lvl))
124     ++lvl;
125 
126   if (*lvl)
127     return 0;
128   else
129     return 1;
130 }
131 
132 int
arch_valid_config_name(const t_uchar * name)133 arch_valid_config_name (const t_uchar * name)
134 {
135   return is_non_upwards_relative_path (name);
136 }
137 
138 
139 /*(c arch_valid_package_name)
140  * int arch_valid_package_name (const t_uchar * name,
141  *                              enum arch_valid_package_name_archive archive_disposition,
142  *                              enum arch_valid_package_name_types type,
143  *                              int tolerant);
144  *
145  * Return non-0 if `name' is a valid arch name of the sort described by
146  * the other arguments.
147  *
148  * `archive_disposition' may be any of the values:
149  *
150  *         arch_no_archive      the name must not be fully qualified (must have no
151  *                              no archive name component)
152  *
153  *         arch_maybe_archive   the name _may_ be fully qualified
154  *
155  *         arch_req_archive     the name _must_ be fully qualified
156  *
157  *
158  * `type' may be any of the values:
159  *
160  *         arch_req_category    the name must have at least a category
161  *
162  *         arch_req_package     the name must have a category and may
163  *                              have a branch label
164  *
165  *         arch_req_version     the name must have a version id
166  *                              (and therefore must have a category and
167  *                              may have a branch label)
168  *
169  *         arch_req_patch_level the name must have a category, may have a
170  *                              branch label, must have a version id, and
171  *                              must have a revision name
172  *
173  * `tolerant':
174  *
175  *         if 0, then the name may not have any components beyond those
176  *         required by `type'.  For example, if type is `arch_req_category',
177  *         then the name may not have a branch label or version id.
178  *
179  *         if 1, then the name may have additional components
180  */
181 int
arch_valid_package_name(const t_uchar * name,enum arch_valid_package_name_archive archive_disposition,enum arch_valid_package_name_types type,int tolerant)182 arch_valid_package_name (const t_uchar * name,
183                          enum arch_valid_package_name_archive archive_disposition,
184                          enum arch_valid_package_name_types type,
185                          int tolerant)
186 {
187   int has_archive;
188   int has_category;
189   int has_branch;
190   int has_version;
191   int has_patch_level;
192   const t_uchar * next;
193 
194   if (!name)
195     return 0;
196 
197   has_archive = 0;
198   has_category = 0;
199   has_branch = 0;
200   has_version = 0;
201   has_patch_level = 0;
202 
203   next = over_opt_archive_prefix (name);
204 
205   has_archive = (next && (next != name));
206 
207   switch (archive_disposition)
208     {
209     case arch_maybe_archive:
210       {
211         if (!next)
212           return 0;
213         break;
214       }
215 
216     case arch_req_archive:
217       {
218         if (!next || (next == name))
219           return 0;
220         break;
221       }
222 
223     case arch_no_archive:
224       {
225         if (!next || (next != name))
226           return 0;
227         break;
228       }
229     }
230 
231   name = next;
232 
233 
234   name = over_basename (name);
235   if (!name)
236     return 0;
237   else
238     has_category = 1;
239 
240   if (*name)
241     {
242       name = over_separator (name);
243       if (!name)
244         return 0;
245 
246       next = over_basename (name);
247       if (next)
248         {
249           has_branch = 1;
250           name = next;
251           if (*name)
252             {
253               name = over_separator (name);
254               if (!name)
255                 return 0;
256             }
257         }
258 
259       if (*name)
260         {
261           name = over_version (name);
262           if (!name)
263             return 0;
264           has_version = 1;
265 
266           if (*name)
267             {
268               name = over_separator (name);
269               if (!name)
270                 return 0;
271 
272               name = over_patch_level (name);
273               if (!name || *name)
274                 return 0;
275 
276               has_patch_level = 1;
277             }
278         }
279     }
280 
281   switch (type)
282     {
283     case arch_req_category:
284       {
285         if (tolerant)
286           return 1;
287         else
288           return !has_branch && !has_version;
289         break;
290       }
291 
292     case arch_req_package:
293       {
294         if (tolerant)
295           return 1;
296         else
297           return !has_version;
298         break;
299       }
300 
301     case arch_req_version:
302       {
303         if (tolerant)
304           return has_version;
305         else
306           return has_version && !has_patch_level;
307         break;
308       }
309 
310     case arch_req_patch_level:
311       {
312         return has_patch_level;
313       }
314 
315     default:
316       {
317         panic ("arch_valid_package_name: bad argument.");
318         return 0;
319       }
320     }
321 }
322 
323 
324 
325 /*(c arch_is_system_package_name)
326  * int arch_is_system_package_name (const t_uchar * name);
327  *
328  * Return non-0 if `name' is a system package name.
329  */
330 int
arch_is_system_package_name(const t_uchar * name)331 arch_is_system_package_name (const t_uchar * name)
332 {
333   t_uchar * package = 0;
334   int answer;
335 
336   package = arch_parse_package_name (arch_ret_package, 0, name);
337   answer = !!str_chr_index (name, '%');
338   lim_free (0, package);
339   return answer;
340 }
341 
342 
343 /*(c arch_parse_package_name)
344  * t_uchar * arch_parse_package_name (enum arch_parse_package_name_type type,
345  *                                    const t_uchar * default_archive,
346  *                                    const t_uchar * name);
347  *
348  * Parse a package name.
349  *
350  * `type' may be any of the values:
351  *
352  *         arch_ret_archive          Return the archive component of the name,
353  *                                   or the value `default_archive' if the name
354  *                                   is not fully qualified.
355  *
356  *         arch_ret_non_archive      Return all of the name except its (optional)
357  *                                   archive component.
358  *
359  *         arch_ret_category         Return just the category name.
360  *
361  *         arch_ret_package          Return the category--branch if the name has a
362  *                                   branch label, just category otherwise.
363  *
364  *         arch_ret_version          Return just the version id of the name.
365  *
366  *         arch_ret_package_version  Return the category(--branch)?--version
367  *                                   of the name
368  *
369  *        arch_ret_patch_level       Return just the revision id of the name
370  *
371  *
372  * Note that there is no `arch_ret_branch' (since not all names have branch labels)
373  * and no `arch_ret_package_patch_level' (since `arch_ret_non_archive' will do that
374  * job).
375  *
376  * `default_archive' is the archive name to use for `arch_ret_archive' if the
377  * name is not fully qualified.   Typically, the value of `default_archive'
378  * is taken from a command-line -A argument or the user's .arch-params/=default-archive
379  * file.
380  *
381  * `name' is the name to parse.
382  *
383  */
384 t_uchar *
arch_parse_package_name(enum arch_parse_package_name_type type,const t_uchar * default_archive,const t_uchar * name)385 arch_parse_package_name (enum arch_parse_package_name_type type,
386                          const t_uchar * default_archive,
387                          const t_uchar * name)
388 {
389   if (!arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1))
390   {
391       safe_printfmt(2, "Invalid revision name %s provided\n", name);
392       return 0;
393   }
394   /*invariant (arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1));*/
395 
396   switch (type)
397     {
398     default:
399       panic ("bad argument to arch_parse_package_name");
400       return 0;                 /* notreached */
401       break;
402 
403     case arch_ret_archive:
404       {
405         t_uchar * slash;
406 
407         slash = str_chr_index (name, '/');
408         if (!slash)
409           {
410             t_uchar * answer = 0;
411             answer = arch_my_default_archive (default_archive);
412             if (!answer)
413               {
414                 safe_printfmt (2, "arch: no default archive set\n");
415                 exit (2);
416               }
417             return answer;
418           }
419         else
420           {
421             return str_save_n (0, name, slash - name);
422           }
423         break;
424       }
425 
426     case arch_ret_non_archive:
427       {
428         t_uchar * slash;
429 
430         slash = str_chr_index (name, '/');
431         if (!slash)
432           return str_save (0, name);
433         else
434           return str_save (0, slash + 1);
435 
436         break;
437       }
438 
439     case arch_ret_category:
440       {
441         const t_uchar * cat_end;
442 
443         name = over_opt_archive_prefix (name);
444         cat_end = over_basename (name);
445         return str_save_n (0, name, cat_end - name);
446         break;
447       }
448 
449     case arch_ret_branch:
450       {
451         const t_uchar * branch_end;
452 
453         name = over_opt_archive_prefix (name);
454         name = over_basename (name); /* over category */
455         name = over_separator (name);
456         if (!name)
457           return str_save (0, "");
458         branch_end = over_basename (name);
459         if (!branch_end)
460           return str_save (0, "");
461         return str_save_n (0, name, branch_end - name);
462         break;
463       }
464 
465     case arch_ret_package:
466       {
467         const t_uchar * branch_end;
468         const t_uchar * t;
469 
470         name = over_opt_archive_prefix (name);
471         branch_end = over_basename (name);
472         t = over_separator (branch_end);
473         if (!t)
474           return str_save (0, name); /* only category provided */
475         branch_end = over_basename (t); /* over category */
476         if (!branch_end)
477           return str_save_n (0, name, (t - 2) - name); /* category--version */
478         else
479           return str_save_n (0, name, branch_end - name);
480         break;
481       }
482 
483     case arch_ret_version:
484       {
485         const t_uchar * version_start;
486         const t_uchar * version_end;
487         const t_uchar * t;
488 
489         name = over_opt_archive_prefix (name);
490         version_end = over_basename (name); /* over category */
491         version_end = over_separator (version_end);
492         invariant (!!version_end);
493         version_start = version_end;
494         t = over_basename (version_start); /* maybe over explicit branch */
495         if (t)
496           {
497             version_end = over_separator (t);
498             invariant (!!version_end);
499             version_start = version_end;
500           }
501         version_end = over_version (version_end);
502         invariant (!!version_end);
503         return str_save_n (0, version_start, version_end - version_start);
504         break;
505       }
506 
507     case arch_ret_patch_level:
508       {
509         const t_uchar * t;
510 
511         name = over_opt_archive_prefix (name);
512         invariant (!!name);
513         name = over_basename (name);
514         invariant (!!name);
515         name = over_separator (name);
516         invariant (!!name);
517         t = over_basename (name); /* maybe over explicit branch */
518         if (t)
519           {
520             name = over_separator (t);
521             invariant (!!name);
522           }
523         name = over_version (name);
524         invariant (!!name);
525         invariant (name[0]);
526         name = over_separator (name);
527         invariant (!!name);
528         invariant (name[0]);
529         return str_save (0, name);
530         break;
531       }
532 
533     case arch_ret_package_version:
534       {
535         const t_uchar * version_start;
536         const t_uchar * version_end;
537         const t_uchar * t;
538 
539         name = over_opt_archive_prefix (name);
540         version_end = over_basename (name); /* over category */
541         version_end = over_separator (version_end);
542         invariant (!!version_end);
543         version_start = version_end;
544         t = over_basename (version_start); /* maybe over explicit branch */
545         if (t)
546           {
547             version_end = over_separator (t);
548             invariant (!!version_end);
549             version_start = version_end;
550           }
551         version_end = over_version (version_end);
552         invariant (!!version_end);
553         return str_save_n (0, name, version_end - name);
554         break;
555       }
556     }
557 }
558 
559 t_uchar *
arch_fully_qualify(const t_uchar * default_archive,const t_uchar * name)560 arch_fully_qualify (const t_uchar * default_archive,
561                     const t_uchar * name)
562 {
563   invariant (arch_valid_package_name (name, arch_maybe_archive, arch_req_package, 1));
564   if (default_archive)
565     invariant (arch_valid_archive_name (default_archive));
566 
567   if (str_chr_index (name, '/'))
568     return str_save (0, name);
569   else
570     {
571       if (!default_archive)
572         default_archive = arch_my_default_archive (0);
573 
574       if (!default_archive)
575         panic ("arch: no default archive set");
576 
577       return str_alloc_cat_many (0, default_archive, "/", name, str_end);
578     }
579 }
580 
581 int
arch_names_cmp(const t_uchar * a,const t_uchar * b)582 arch_names_cmp (const t_uchar * a,
583                 const t_uchar * b)
584 {
585   const t_uchar * a_nxt;
586   const t_uchar * b_nxt;
587   int res;
588 
589   /* compare archive name
590    */
591   a_nxt = over_opt_archive_prefix (a);
592   b_nxt = over_opt_archive_prefix (b);
593 
594   res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
595 
596   if (res)
597     return res;
598 
599   a = a_nxt;
600   b = b_nxt;
601 
602   /* compare category name
603    */
604 
605   a_nxt = over_basename (a);
606   b_nxt = over_basename (b);
607 
608   res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
609 
610   if (res)
611     return res;
612 
613   if (!*a_nxt && !*b_nxt)
614     return 0;
615 
616   if (!*a_nxt)
617     return -1;
618 
619   if (!*b_nxt)
620     return 1;
621 
622   a = over_separator (a_nxt);
623   b = over_separator (b_nxt);
624 
625 
626   /* compare branch names
627    */
628 
629   a_nxt = over_basename (a);
630   b_nxt = over_basename (b);
631 
632   if (a_nxt && !b_nxt)
633     {
634       /* a has a branch, b does not */
635       return 1;
636     }
637   else if (!a_nxt && b_nxt)
638     {
639       /* b has a branch, a does not */
640       return -1;
641     }
642   else if (a_nxt && b_nxt)
643     {
644       /* both have branch names */
645 
646       res = str_cmp_n (a, a_nxt - a, b, b_nxt - b);
647 
648       if (res)
649         return res;
650 
651       if (!*a_nxt && !*b_nxt)
652         return 0;
653 
654       if (!*a_nxt)
655         return -1;
656 
657       if (!*b_nxt)
658         return 1;
659 
660       a = over_separator (a_nxt);
661       b = over_separator (b_nxt);
662     }
663 
664   /* compare version names
665    */
666 
667   a_nxt = over_version (a);
668   b_nxt = over_version (b);
669 
670   {
671     int a_vsn_len;
672     int b_vsn_len;
673 
674     a_vsn_len = a_nxt - a;
675     b_vsn_len = b_nxt - b;
676 
677     /* precondition:
678      *    a and b point to a version number component
679      *    a_vsn_len and b_vsn_len tell how many chars remain in the version id
680      *
681      * postcondition:
682      *    RETURNS if version ids differ
683      *    a and b point past version id otherwise
684      *
685      * goal:
686      *    compare dot-separated components numerically
687      *    noting that a and b may have different numbers of components
688      */
689     while (1)
690       {
691         int errn;
692         const t_uchar * a_comp_end;
693         const t_uchar * b_comp_end;
694         t_ulong a_comp;
695         t_ulong b_comp;
696 
697         a_comp_end = str_chr_index_n (a, a_vsn_len, '.');
698         if (!a_comp_end)
699           a_comp_end = a + a_vsn_len;
700 
701         b_comp_end = str_chr_index_n (b, b_vsn_len, '.');
702         if (!b_comp_end)
703           b_comp_end = b + b_vsn_len;
704 
705         invariant (!cvt_decimal_to_ulong (&errn, &a_comp, a, a_comp_end - a));
706         invariant (!cvt_decimal_to_ulong (&errn, &b_comp, b, b_comp_end - b));
707 
708         if (a_comp < b_comp)
709           return -1;
710         else if (a_comp > b_comp)
711           return 1;
712         else
713           {
714             a_vsn_len -= (a_comp_end - a);
715             b_vsn_len -= (b_comp_end - b);
716 
717             if (a_vsn_len && b_vsn_len)
718               {
719                 /* both have additional components
720                  */
721                 a = a_comp_end + 1;
722                 b = b_comp_end + 1;
723                 --a_vsn_len;
724                 --b_vsn_len;
725               }
726             else if (!a_vsn_len && b_vsn_len)
727               {
728                 /* b has more components, a doesn't.
729                  */
730                 return -1;
731               }
732             else if (a_vsn_len && !b_vsn_len)
733               {
734                 /* a has more components, b doesn't.
735                  */
736                 return 1;
737               }
738             else
739               {
740                 /* neither has more components
741                  */
742                 a = a_comp_end;
743                 b = b_comp_end;
744                 break;
745               }
746           }
747       }
748 
749     a_nxt = over_separator (a);
750     b_nxt = over_separator (b);
751 
752     if (!a_nxt && !b_nxt)
753       return 0;
754     else if (a_nxt && !b_nxt)
755       return 1;
756     else if (!a_nxt && b_nxt)
757       return -1;
758     else
759       {
760         a = a_nxt;
761         b = b_nxt;
762       }
763   }
764 
765 
766 
767   /* compare patch level phase
768    */
769   {
770     t_uchar * a_dash;
771     t_uchar * b_dash;
772 
773     a_dash = str_chr_index (a, '-');
774     b_dash = str_chr_index (b, '-');
775 
776     invariant (a && b);
777 
778     res = str_cmp_n (a, a_dash - a, b, b_dash - b);
779     if (res)
780       return res;
781 
782     a = a_dash + 1;
783     b = b_dash + 1;
784   }
785 
786   /* compare patch level numbers
787    */
788   {
789     int errn;
790     t_ulong a_lvl;
791     t_ulong b_lvl;
792 
793     invariant (!cvt_decimal_to_ulong (&errn, &a_lvl, a, str_length (a)));
794     invariant (!cvt_decimal_to_ulong (&errn, &b_lvl, b, str_length (b)));
795 
796     if (a_lvl < b_lvl)
797       return -1;
798     else if (a_lvl > b_lvl)
799       return 1;
800     else
801       return 0;
802   }
803 }
804 
805 void
arch_sort_table_by_name_field(int reverse_p,rel_table table,int field)806 arch_sort_table_by_name_field (int reverse_p, rel_table table, int field)
807 {
808   rel_sort_table_by_field_fn (reverse_p, table, field, arch_names_cmp);
809 }
810 
811 void
arch_sort_table_by_patch_level_field(int reverse_p,rel_table table,int field)812 arch_sort_table_by_patch_level_field (int reverse_p, rel_table table, int field)
813 {
814   rel_sort_table_by_field_fn (reverse_p, table, field, arch_patch_lvl_cmp);
815 }
816 
817 int
arch_patch_lvl_cmp(const t_uchar * a,const t_uchar * b)818 arch_patch_lvl_cmp (const t_uchar * a,
819                     const t_uchar * b)
820 {
821   t_uchar * a_dash;
822   t_uchar * b_dash;
823   int res;
824   t_ulong a_lvl;
825   t_ulong b_lvl;
826   int errn;
827 
828   a_dash = str_chr_index (a, '-');
829   b_dash = str_chr_index (b, '-');
830   invariant (a_dash && b_dash);
831 
832   res = str_cmp_n (a, a_dash - a, b, b_dash - b);
833   if (res)
834     return res;
835 
836   invariant (!cvt_decimal_to_ulong (&errn, &a_lvl, a_dash + 1, str_length (a_dash + 1)));
837   invariant (!cvt_decimal_to_ulong (&errn, &b_lvl, b_dash + 1, str_length (b_dash + 1)));
838 
839   if (a_lvl < b_lvl)
840     return -1;
841   else if (a_lvl > b_lvl)
842     return 1;
843   else
844     return 0;
845 }
846 
847 
848 rel_table
arch_pick_archives_by_field(rel_table in,int field)849 arch_pick_archives_by_field (rel_table in, int field)
850 {
851   rel_table answer = rel_table_nil;
852   int x;
853 
854   for (x = 0; x < rel_n_records (in); ++x)
855     {
856       if (arch_valid_archive_name (rel_peek_str (in, x, field)))
857         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
858     }
859 
860   return answer;
861 }
862 
863 
864 rel_table
arch_pick_categories_by_field(rel_table in,int field)865 arch_pick_categories_by_field (rel_table in, int field)
866 {
867   rel_table answer = rel_table_nil;
868   int x;
869 
870   for (x = 0; x < rel_n_records (in); ++x)
871     {
872       if (arch_valid_package_name (rel_peek_str (in, x, field), arch_no_archive, arch_req_category, 0))
873         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
874     }
875 
876   return answer;
877 }
878 
879 rel_table
arch_pick_branches_by_field(rel_table in,int field)880 arch_pick_branches_by_field (rel_table in, int field)
881 {
882   rel_table answer = rel_table_nil;
883   int x;
884 
885   for (x = 0; x < rel_n_records (in); ++x)
886     {
887       if (arch_valid_package_name (rel_peek_str (in, x, field), arch_no_archive, arch_req_package, 0))
888         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
889     }
890 
891   return answer;
892 }
893 
894 rel_table
arch_pick_versions_by_field(rel_table in,int field)895 arch_pick_versions_by_field (rel_table in, int field)
896 {
897   rel_table answer = rel_table_nil;
898   int x;
899 
900   for (x = 0; x < rel_n_records (in); ++x)
901     {
902       if (arch_valid_package_name (rel_peek_str (in, x, field), arch_no_archive, arch_req_version, 0))
903         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
904     }
905 
906   return answer;
907 }
908 
909 rel_table
arch_pick_revisions_by_field(rel_table in,int field)910 arch_pick_revisions_by_field (rel_table in, int field)
911 {
912   rel_table answer = rel_table_nil;
913   int x;
914 
915   for (x = 0; x < rel_n_records (in); ++x)
916     {
917       if (arch_valid_package_name (rel_peek_str (in, x, field), arch_no_archive, arch_req_patch_level, 0))
918         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
919     }
920 
921   return answer;
922 }
923 
924 rel_table
arch_pick_patch_levels_by_field(rel_table in,int field)925 arch_pick_patch_levels_by_field (rel_table in, int field)
926 {
927   rel_table answer = rel_table_nil;
928   int x;
929 
930   for (x = 0; x < rel_n_records (in); ++x)
931     {
932       if (arch_valid_patch_level_name (rel_peek_str (in, x, field)))
933         rel_add_records (&answer, rel_copy_record (rel_peek_record (in, x)), rel_record_null);
934     }
935 
936   return answer;
937 }
938 
939 
940 enum arch_patch_level_type
arch_analyze_patch_level(t_ulong * n,const t_uchar * patch_level)941 arch_analyze_patch_level (t_ulong * n,
942                           const t_uchar * patch_level)
943 {
944   int ign;
945   enum arch_patch_level_type type;
946   const t_uchar * n_str;
947 
948   if (!str_cmp ("base-0", patch_level))
949     {
950       *n = 0;
951       return arch_is_base0_level;
952     }
953   else if (!str_cmp_prefix ("patch-", patch_level))
954     {
955       type = arch_is_patch_level;
956       n_str = patch_level + sizeof ("patch-") - 1;
957     }
958   else if (!str_cmp_prefix ("version-", patch_level))
959     {
960       type = arch_is_version_level;
961       n_str = patch_level + sizeof ("version-") - 1;
962     }
963   else if (!str_cmp_prefix ("versionfix-", patch_level))
964     {
965       type = arch_is_versionfix_level;
966       n_str = patch_level + sizeof ("versionfix-") - 1;
967     }
968   else
969     panic ("illegal patch_level in arch_analyze_patch_level");
970 
971  if (cvt_decimal_to_ulong (&ign, n, n_str, str_length (n_str)))
972    panic ("illegal patch_level in arch_analyze_patch_level");
973 
974   return type;
975 }
976 
977 
978 t_uchar *
arch_form_patch_level(enum arch_patch_level_type type,t_ulong n)979 arch_form_patch_level (enum arch_patch_level_type type, t_ulong n)
980 {
981   t_uchar n_buf[64];
982 
983   cvt_ulong_to_decimal (n_buf, n);
984 
985   switch (type)
986     {
987     case arch_is_base0_level:
988       {
989         return str_save (0, "base-0");
990       }
991     case arch_is_patch_level:
992       {
993         return str_alloc_cat (0, "patch-", n_buf);
994       }
995     case arch_is_version_level:
996       {
997         return str_alloc_cat (0, "version-", n_buf);
998       }
999     case arch_is_versionfix_level:
1000       {
1001         return str_alloc_cat (0, "versionfix-", n_buf);
1002       }
1003     default:
1004       {
1005         panic ("not reached in arch_form_patch_level");
1006         return 0;
1007       }
1008     }
1009 }
1010 
1011 
1012 
1013 static const t_uchar *
over_opt_archive_prefix(const t_uchar * name)1014 over_opt_archive_prefix (const t_uchar * name)
1015 {
1016   const t_uchar * slash;
1017   const t_uchar * archive_name_end;
1018 
1019   slash = (const t_uchar *)str_chr_index (name, '/');
1020 
1021   if (!slash)
1022     return name;
1023 
1024   archive_name_end = over_archive_name (name);
1025 
1026   if (archive_name_end != slash)
1027     return 0;
1028 
1029   return slash + 1;
1030 }
1031 
1032 
1033 #define char_is_alnum_or_dash(c) (char_is_alnum (c) || (c == '-'))
1034 
1035 static const t_uchar *
over_archive_name(const t_uchar * in)1036 over_archive_name (const t_uchar * in)
1037 {
1038   if (!char_is_alnum_or_dash (*in))
1039     return 0;
1040 
1041   while (1)
1042     {
1043       while (char_is_alnum_or_dash (*in))
1044         ++in;
1045 
1046       if (*in != '.' && *in != '_')
1047         break;
1048 
1049       if (!char_is_alnum_or_dash (in[1]))
1050         return 0;
1051 
1052       ++in;
1053     }
1054 
1055   if (*in != '@')
1056     return 0;
1057 
1058   ++in;
1059 
1060   while (char_is_alnum_or_dash(*in) || (*in == '.'))
1061     {
1062       if ((*in == '-') && (in[1] == '-'))
1063         break;
1064       ++in;
1065     }
1066 
1067   if (!*in || (*in == '/'))
1068     return in;
1069 
1070   if ((in[0] != '-') || (in[1] != '-'))
1071     return 0;
1072 
1073   in += 2;
1074 
1075   while (char_is_alnum_or_dash(*in) || (*in == '.'))
1076     ++in;
1077 
1078   if (*in && (*in != '/'))
1079     return 0;
1080 
1081   return in;
1082 }
1083 
1084 
1085 static const t_uchar *
over_basename(const t_uchar * in)1086 over_basename (const t_uchar * in)
1087 {
1088   if (!char_is_alpha (*in))
1089     return 0;
1090   ++in;
1091 
1092   while (1)
1093     {
1094       if (!*in)
1095         return in;
1096       else if ((char_is_alnum (*in)) || (*in == '%') || (*in == ','))
1097         ++in;
1098       else if (*in == '-')
1099         {
1100           if (in[1] == '-')
1101             return in;
1102           else
1103             ++in;
1104         }
1105       else
1106         break;
1107     }
1108   return 0;
1109 }
1110 
1111 static const t_uchar *
over_separator(const t_uchar * in)1112 over_separator (const t_uchar * in)
1113 {
1114   if ((*in == '-') && (in[1] == '-'))
1115     return in + 2;
1116   else
1117     return 0;
1118 }
1119 
1120 static const t_uchar *
over_version(const t_uchar * in)1121 over_version (const t_uchar * in)
1122 {
1123   while (1)
1124     {
1125       if (!*in)
1126         break;
1127       else if (!char_is_digit (*in))
1128         break;
1129       else
1130         {
1131           while (char_is_digit (*in))
1132             ++in;
1133           if (!*in)
1134             return in;
1135           else if (*in == '.')
1136             ++in;
1137           else if ((*in == '-') && (in[1] == '-'))
1138             return in;
1139           else
1140             break;
1141         }
1142     }
1143   return 0;
1144 }
1145 
1146 static const t_uchar *
over_patch_level(const t_uchar * in)1147 over_patch_level (const t_uchar * in)
1148 {
1149   if (!str_cmp (in, "base-0"))
1150     return in + sizeof ("base-0") - 1;
1151   else
1152     {
1153       int prefix_len;
1154 
1155       if (!str_cmp_prefix ("patch-", in))
1156         prefix_len = sizeof ("patch-") - 1;
1157       else if (!str_cmp_prefix ("version-", in))
1158         prefix_len = sizeof ("version-") - 1;
1159       else if (!str_cmp_prefix ("versionfix-", in))
1160         prefix_len = sizeof ("versionfix-") - 1;
1161       else
1162         return 0;
1163 
1164       in += prefix_len;
1165 
1166       if (!char_is_digit (*in))
1167         return 0;
1168 
1169       while (char_is_digit (*in))
1170         ++in;
1171 
1172       if (*in)
1173         return 0;
1174 
1175       return in;
1176     }
1177 }
1178 
1179 
1180 
1181 
1182 /* tag: Tom Lord Mon May 12 10:17:47 2003 (namespace.c)
1183  */
1184