FieldsCore.pm 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. # Copyright © 2007-2009 Raphaël Hertzog <hertzog@debian.org>
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. package Dpkg::Control::FieldsCore;
  16. use strict;
  17. use warnings;
  18. our $VERSION = '1.00';
  19. use Exporter qw(import);
  20. use Dpkg::Gettext;
  21. use Dpkg::ErrorHandling;
  22. use Dpkg::Control::Types;
  23. use Dpkg::Checksums;
  24. our @EXPORT = qw(field_capitalize field_is_official field_is_allowed_in
  25. field_transfer_single field_transfer_all
  26. field_list_src_dep field_list_pkg_dep field_get_dep_type
  27. field_get_sep_type
  28. field_ordered_list field_register
  29. field_insert_after field_insert_before
  30. FIELD_SEP_UNKNOWN FIELD_SEP_SPACE FIELD_SEP_COMMA
  31. FIELD_SEP_LINE);
  32. use constant {
  33. ALL_PKG => CTRL_INFO_PKG | CTRL_INDEX_PKG | CTRL_PKG_DEB | CTRL_FILE_STATUS,
  34. ALL_SRC => CTRL_INFO_SRC | CTRL_INDEX_SRC | CTRL_PKG_SRC,
  35. ALL_CHANGES => CTRL_FILE_CHANGES | CTRL_CHANGELOG,
  36. };
  37. use constant {
  38. FIELD_SEP_UNKNOWN => 0,
  39. FIELD_SEP_SPACE => 1,
  40. FIELD_SEP_COMMA => 2,
  41. FIELD_SEP_LINE => 4,
  42. };
  43. # The canonical list of fields
  44. # Note that fields used only in dpkg's available file are not listed
  45. # Deprecated fields of dpkg's status file are also not listed
  46. our %FIELDS = (
  47. 'Architecture' => {
  48. allowed => (ALL_PKG | ALL_SRC | CTRL_FILE_CHANGES) & (~CTRL_INFO_SRC),
  49. separator => FIELD_SEP_SPACE,
  50. },
  51. 'Binary' => {
  52. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  53. # XXX: This field values are separated either by space or comma
  54. # depending on the context.
  55. separator => FIELD_SEP_SPACE | FIELD_SEP_COMMA,
  56. },
  57. 'Binary-Only' => {
  58. allowed => ALL_CHANGES,
  59. },
  60. 'Breaks' => {
  61. allowed => ALL_PKG,
  62. separator => FIELD_SEP_COMMA,
  63. dependency => 'union',
  64. dep_order => 7,
  65. },
  66. 'Bugs' => {
  67. allowed => (ALL_PKG | CTRL_INFO_SRC | CTRL_FILE_VENDOR) & (~CTRL_INFO_PKG),
  68. },
  69. 'Build-Conflicts' => {
  70. allowed => ALL_SRC,
  71. separator => FIELD_SEP_COMMA,
  72. dependency => 'union',
  73. dep_order => 4,
  74. },
  75. 'Build-Conflicts-Arch' => {
  76. allowed => ALL_SRC,
  77. separator => FIELD_SEP_COMMA,
  78. dependency => 'union',
  79. dep_order => 5,
  80. },
  81. 'Build-Conflicts-Indep' => {
  82. allowed => ALL_SRC,
  83. separator => FIELD_SEP_COMMA,
  84. dependency => 'union',
  85. dep_order => 6,
  86. },
  87. 'Build-Depends' => {
  88. allowed => ALL_SRC,
  89. separator => FIELD_SEP_COMMA,
  90. dependency => 'normal',
  91. dep_order => 1,
  92. },
  93. 'Build-Depends-Arch' => {
  94. allowed => ALL_SRC,
  95. separator => FIELD_SEP_COMMA,
  96. dependency => 'normal',
  97. dep_order => 2,
  98. },
  99. 'Build-Depends-Indep' => {
  100. allowed => ALL_SRC,
  101. separator => FIELD_SEP_COMMA,
  102. dependency => 'normal',
  103. dep_order => 3,
  104. },
  105. 'Build-Profiles' => {
  106. allowed => CTRL_INFO_PKG,
  107. separator => FIELD_SEP_SPACE,
  108. },
  109. 'Built-For-Profiles' => {
  110. allowed => ALL_PKG | CTRL_FILE_CHANGES,
  111. separator => FIELD_SEP_SPACE,
  112. },
  113. 'Built-Using' => {
  114. allowed => ALL_PKG,
  115. separator => FIELD_SEP_COMMA,
  116. dependency => 'union',
  117. dep_order => 10,
  118. },
  119. 'Changed-By' => {
  120. allowed => CTRL_FILE_CHANGES,
  121. },
  122. 'Changes' => {
  123. allowed => ALL_CHANGES,
  124. },
  125. 'Closes' => {
  126. allowed => ALL_CHANGES,
  127. separator => FIELD_SEP_SPACE,
  128. },
  129. 'Conffiles' => {
  130. allowed => CTRL_FILE_STATUS,
  131. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
  132. },
  133. 'Config-Version' => {
  134. allowed => CTRL_FILE_STATUS,
  135. },
  136. 'Conflicts' => {
  137. allowed => ALL_PKG,
  138. separator => FIELD_SEP_COMMA,
  139. dependency => 'union',
  140. dep_order => 6,
  141. },
  142. 'Date' => {
  143. allowed => ALL_CHANGES,
  144. },
  145. 'Depends' => {
  146. allowed => ALL_PKG,
  147. separator => FIELD_SEP_COMMA,
  148. dependency => 'normal',
  149. dep_order => 2,
  150. },
  151. 'Description' => {
  152. allowed => ALL_PKG | CTRL_FILE_CHANGES,
  153. },
  154. 'Directory' => {
  155. allowed => CTRL_INDEX_SRC,
  156. },
  157. 'Distribution' => {
  158. allowed => ALL_CHANGES,
  159. },
  160. 'Enhances' => {
  161. allowed => ALL_PKG,
  162. separator => FIELD_SEP_COMMA,
  163. dependency => 'union',
  164. dep_order => 5,
  165. },
  166. 'Essential' => {
  167. allowed => ALL_PKG,
  168. },
  169. 'Filename' => {
  170. allowed => CTRL_INDEX_PKG,
  171. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
  172. },
  173. 'Files' => {
  174. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  175. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
  176. },
  177. 'Format' => {
  178. allowed => CTRL_PKG_SRC | CTRL_FILE_CHANGES,
  179. },
  180. 'Homepage' => {
  181. allowed => ALL_SRC | ALL_PKG,
  182. },
  183. 'Installed-Size' => {
  184. allowed => ALL_PKG & ~CTRL_INFO_PKG,
  185. },
  186. 'Installer-Menu-Item' => {
  187. allowed => ALL_PKG,
  188. },
  189. 'Kernel-Version' => {
  190. allowed => ALL_PKG,
  191. },
  192. 'Origin' => {
  193. allowed => (ALL_PKG | ALL_SRC) & (~CTRL_INFO_PKG),
  194. },
  195. 'Maintainer' => {
  196. allowed => CTRL_PKG_DEB | ALL_SRC | ALL_CHANGES,
  197. },
  198. 'Multi-Arch' => {
  199. allowed => ALL_PKG,
  200. },
  201. 'Package' => {
  202. allowed => ALL_PKG,
  203. },
  204. 'Package-List' => {
  205. allowed => ALL_SRC & ~CTRL_INFO_SRC,
  206. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
  207. },
  208. 'Package-Type' => {
  209. allowed => ALL_PKG,
  210. },
  211. 'Parent' => {
  212. allowed => CTRL_FILE_VENDOR,
  213. },
  214. 'Pre-Depends' => {
  215. allowed => ALL_PKG,
  216. separator => FIELD_SEP_COMMA,
  217. dependency => 'normal',
  218. dep_order => 1,
  219. },
  220. 'Priority' => {
  221. allowed => CTRL_INFO_SRC | CTRL_INDEX_SRC | ALL_PKG,
  222. },
  223. 'Provides' => {
  224. allowed => ALL_PKG,
  225. separator => FIELD_SEP_COMMA,
  226. dependency => 'union',
  227. dep_order => 9,
  228. },
  229. 'Recommends' => {
  230. allowed => ALL_PKG,
  231. separator => FIELD_SEP_COMMA,
  232. dependency => 'normal',
  233. dep_order => 3,
  234. },
  235. 'Replaces' => {
  236. allowed => ALL_PKG,
  237. separator => FIELD_SEP_COMMA,
  238. dependency => 'union',
  239. dep_order => 8,
  240. },
  241. 'Section' => {
  242. allowed => CTRL_INFO_SRC | CTRL_INDEX_SRC | ALL_PKG,
  243. },
  244. 'Size' => {
  245. allowed => CTRL_INDEX_PKG,
  246. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE,
  247. },
  248. 'Source' => {
  249. allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES) &
  250. (~(CTRL_INDEX_SRC | CTRL_INFO_PKG)),
  251. },
  252. 'Standards-Version' => {
  253. allowed => ALL_SRC,
  254. },
  255. 'Status' => {
  256. allowed => CTRL_FILE_STATUS,
  257. separator => FIELD_SEP_SPACE,
  258. },
  259. 'Subarchitecture' => {
  260. allowed => ALL_PKG,
  261. },
  262. 'Suggests' => {
  263. allowed => ALL_PKG,
  264. separator => FIELD_SEP_COMMA,
  265. dependency => 'normal',
  266. dep_order => 4,
  267. },
  268. 'Tag' => {
  269. allowed => ALL_PKG,
  270. separator => FIELD_SEP_COMMA,
  271. },
  272. 'Task' => {
  273. allowed => ALL_PKG,
  274. },
  275. 'Testsuite' => {
  276. allowed => ALL_SRC,
  277. separator => FIELD_SEP_COMMA,
  278. },
  279. 'Triggers-Awaited' => {
  280. allowed => CTRL_FILE_STATUS,
  281. separator => FIELD_SEP_SPACE,
  282. },
  283. 'Triggers-Pending' => {
  284. allowed => CTRL_FILE_STATUS,
  285. separator => FIELD_SEP_SPACE,
  286. },
  287. 'Uploaders' => {
  288. allowed => ALL_SRC,
  289. separator => FIELD_SEP_COMMA,
  290. },
  291. 'Urgency' => {
  292. allowed => ALL_CHANGES,
  293. },
  294. 'Vcs-Browser' => {
  295. allowed => ALL_SRC,
  296. },
  297. 'Vcs-Arch' => {
  298. allowed => ALL_SRC,
  299. },
  300. 'Vcs-Bzr' => {
  301. allowed => ALL_SRC,
  302. },
  303. 'Vcs-Cvs' => {
  304. allowed => ALL_SRC,
  305. },
  306. 'Vcs-Darcs' => {
  307. allowed => ALL_SRC,
  308. },
  309. 'Vcs-Git' => {
  310. allowed => ALL_SRC,
  311. },
  312. 'Vcs-Hg' => {
  313. allowed => ALL_SRC,
  314. },
  315. 'Vcs-Mtn' => {
  316. allowed => ALL_SRC,
  317. },
  318. 'Vcs-Svn' => {
  319. allowed => ALL_SRC,
  320. },
  321. 'Vendor' => {
  322. allowed => CTRL_FILE_VENDOR,
  323. },
  324. 'Vendor-Url' => {
  325. allowed => CTRL_FILE_VENDOR,
  326. },
  327. 'Version' => {
  328. allowed => (ALL_PKG | ALL_SRC | ALL_CHANGES) &
  329. (~(CTRL_INFO_SRC | CTRL_INFO_PKG)),
  330. },
  331. );
  332. my @checksum_fields = map { &field_capitalize("Checksums-$_") } checksums_get_list();
  333. my @sum_fields = map { $_ eq 'md5' ? 'MD5sum' : &field_capitalize($_) }
  334. checksums_get_list();
  335. &field_register($_, CTRL_PKG_SRC | CTRL_FILE_CHANGES) foreach @checksum_fields;
  336. &field_register($_, CTRL_INDEX_PKG,
  337. separator => FIELD_SEP_LINE | FIELD_SEP_SPACE) foreach @sum_fields;
  338. our %FIELD_ORDER = (
  339. CTRL_PKG_DEB() => [
  340. qw(Package Package-Type Source Version Built-Using Kernel-Version
  341. Built-For-Profiles Architecture Subarchitecture
  342. Installer-Menu-Item Essential Origin Bugs
  343. Maintainer Installed-Size), &field_list_pkg_dep(),
  344. qw(Section Priority Multi-Arch Homepage Description Tag Task)
  345. ],
  346. CTRL_PKG_SRC() => [
  347. qw(Format Source Binary Architecture Version Origin Maintainer
  348. Uploaders Homepage Standards-Version Vcs-Browser
  349. Vcs-Arch Vcs-Bzr Vcs-Cvs Vcs-Darcs Vcs-Git Vcs-Hg Vcs-Mtn
  350. Vcs-Svn Testsuite), &field_list_src_dep(), qw(Package-List),
  351. @checksum_fields, qw(Files)
  352. ],
  353. CTRL_FILE_CHANGES() => [
  354. qw(Format Date Source Binary Binary-Only Built-For-Profiles Architecture
  355. Version Distribution Urgency Maintainer Changed-By Description
  356. Closes Changes),
  357. @checksum_fields, qw(Files)
  358. ],
  359. CTRL_CHANGELOG() => [
  360. qw(Source Binary-Only Version Distribution Urgency Maintainer
  361. Date Closes Changes)
  362. ],
  363. CTRL_FILE_STATUS() => [ # Same as fieldinfos in lib/dpkg/parse.c
  364. qw(Package Essential Status Priority Section Installed-Size Origin
  365. Maintainer Bugs Architecture Multi-Arch Source Version Config-Version
  366. Replaces Provides Depends Pre-Depends Recommends Suggests Breaks
  367. Conflicts Enhances Conffiles Description Triggers-Pending
  368. Triggers-Awaited)
  369. ],
  370. );
  371. # Order for CTRL_INDEX_PKG is derived from CTRL_PKG_DEB
  372. $FIELD_ORDER{CTRL_INDEX_PKG()} = [ @{$FIELD_ORDER{CTRL_PKG_DEB()}} ];
  373. &field_insert_before(CTRL_INDEX_PKG, 'Section', 'Filename', 'Size', @sum_fields);
  374. # Order for CTRL_INDEX_SRC is derived from CTRL_PKG_SRC
  375. $FIELD_ORDER{CTRL_INDEX_SRC()} = [ @{$FIELD_ORDER{CTRL_PKG_SRC()}} ];
  376. @{$FIELD_ORDER{CTRL_INDEX_SRC()}} = map { $_ eq 'Source' ? 'Package' : $_ }
  377. @{$FIELD_ORDER{CTRL_PKG_SRC()}};
  378. &field_insert_after(CTRL_INDEX_SRC, 'Version', 'Priority', 'Section');
  379. &field_insert_before(CTRL_INDEX_SRC, 'Checksums-Md5', 'Directory');
  380. =encoding utf8
  381. =head1 NAME
  382. Dpkg::Control::FieldsCore - manage (list of official) control fields
  383. =head1 DESCRIPTION
  384. The modules contains a list of fieldnames with associated meta-data explaining
  385. in which type of control information they are allowed. The types are the
  386. CTRL_* constants exported by Dpkg::Control.
  387. =head1 FUNCTIONS
  388. =over 4
  389. =item my $f = field_capitalize($field_name)
  390. Returns the field name properly capitalized. All characters are lowercase,
  391. except the first of each word (words are separated by a hyphen in field names).
  392. =cut
  393. sub field_capitalize($) {
  394. my $field = lc(shift);
  395. # Some special cases due to history
  396. return 'MD5sum' if $field eq 'md5sum';
  397. return uc($field) if checksums_is_supported($field);
  398. # Generic case
  399. return join '-', map { ucfirst } split /-/, $field;
  400. }
  401. =item field_is_official($fname)
  402. Returns true if the field is official and known.
  403. =cut
  404. sub field_is_official($) {
  405. my $field = field_capitalize(shift);
  406. return exists $FIELDS{$field};
  407. }
  408. =item field_is_allowed_in($fname, @types)
  409. Returns true (1) if the field $fname is allowed in all the types listed in
  410. the list. Note that you can use type sets instead of individual types (ex:
  411. CTRL_FILE_CHANGES | CTRL_CHANGELOG).
  412. field_allowed_in(A|B, C) returns true only if the field is allowed in C
  413. and either A or B.
  414. Undef is returned for non-official fields.
  415. =cut
  416. sub field_is_allowed_in($@) {
  417. my ($field, @types) = @_;
  418. $field = field_capitalize($field);
  419. return unless field_is_official($field);
  420. return 0 if not scalar(@types);
  421. foreach my $type (@types) {
  422. next if $type == CTRL_UNKNOWN; # Always allowed
  423. return 0 unless $FIELDS{$field}{allowed} & $type;
  424. }
  425. return 1;
  426. }
  427. =item field_transfer_single($from, $to, $field)
  428. If appropriate, copy the value of the field named $field taken from the
  429. $from Dpkg::Control object to the $to Dpkg::Control object.
  430. Official fields are copied only if the field is allowed in both types of
  431. objects. Custom fields are treated in a specific manner. When the target
  432. is not among CTRL_PKG_SRC, CTRL_PKG_DEB or CTRL_FILE_CHANGES, then they
  433. are alway copied as is (the X- prefix is kept). Otherwise they are not
  434. copied except if the target object matches the target destination encoded
  435. in the field name. The initial X denoting custom fields can be followed by
  436. one or more letters among "S" (Source: corresponds to CTRL_PKG_SRC), "B"
  437. (Binary: corresponds to CTRL_PKG_DEB) or "C" (Changes: corresponds to
  438. CTRL_FILE_CHANGES).
  439. Returns undef if nothing has been copied or the name of the new field
  440. added to $to otherwise.
  441. =cut
  442. sub field_transfer_single($$;$) {
  443. my ($from, $to, $field) = @_;
  444. $field //= $_;
  445. my ($from_type, $to_type) = ($from->get_type(), $to->get_type());
  446. $field = field_capitalize($field);
  447. if (field_is_allowed_in($field, $from_type, $to_type)) {
  448. $to->{$field} = $from->{$field};
  449. return $field;
  450. } elsif ($field =~ /^X([SBC]*)-/i) {
  451. my $dest = $1;
  452. if (($dest =~ /B/i and $to_type == CTRL_PKG_DEB) or
  453. ($dest =~ /S/i and $to_type == CTRL_PKG_SRC) or
  454. ($dest =~ /C/i and $to_type == CTRL_FILE_CHANGES))
  455. {
  456. my $new = $field;
  457. $new =~ s/^X([SBC]*)-//i;
  458. $to->{$new} = $from->{$field};
  459. return $new;
  460. } elsif ($to_type != CTRL_PKG_DEB and
  461. $to_type != CTRL_PKG_SRC and
  462. $to_type != CTRL_FILE_CHANGES)
  463. {
  464. $to->{$field} = $from->{$field};
  465. return $field;
  466. }
  467. } elsif (not field_is_allowed_in($field, $from_type)) {
  468. warning(g_("unknown information field '%s' in input data in %s"),
  469. $field, $from->get_option('name') || g_('control information'));
  470. }
  471. return;
  472. }
  473. =item field_transfer_all($from, $to)
  474. Transfer all appropriate fields from $from to $to. Calls
  475. field_transfer_single() on all fields available in $from.
  476. Returns the list of fields that have been added to $to.
  477. =cut
  478. sub field_transfer_all($$) {
  479. my ($from, $to) = @_;
  480. my (@res, $res);
  481. foreach my $k (keys %$from) {
  482. $res = field_transfer_single($from, $to, $k);
  483. push @res, $res if $res and defined wantarray;
  484. }
  485. return @res;
  486. }
  487. =item field_ordered_list($type)
  488. Returns an ordered list of fields for a given type of control information.
  489. This list can be used to output the fields in a predictable order.
  490. The list might be empty for types where the order does not matter much.
  491. =cut
  492. sub field_ordered_list($) {
  493. my ($type) = @_;
  494. return @{$FIELD_ORDER{$type}} if exists $FIELD_ORDER{$type};
  495. return ();
  496. }
  497. =item field_list_src_dep()
  498. List of fields that contains dependencies-like information in a source
  499. Debian package.
  500. =cut
  501. sub field_list_src_dep() {
  502. my @list = sort {
  503. $FIELDS{$a}{dep_order} <=> $FIELDS{$b}{dep_order}
  504. } grep {
  505. field_is_allowed_in($_, CTRL_PKG_SRC) and
  506. exists $FIELDS{$_}{dependency}
  507. } keys %FIELDS;
  508. return @list;
  509. }
  510. =item field_list_pkg_dep()
  511. List of fields that contains dependencies-like information in a binary
  512. Debian package. The fields that express real dependencies are sorted from
  513. the stronger to the weaker.
  514. =cut
  515. sub field_list_pkg_dep() {
  516. my @keys = keys %FIELDS;
  517. my @list = sort {
  518. $FIELDS{$a}{dep_order} <=> $FIELDS{$b}{dep_order}
  519. } grep {
  520. field_is_allowed_in($_, CTRL_PKG_DEB) and
  521. exists $FIELDS{$_}{dependency}
  522. } @keys;
  523. return @list;
  524. }
  525. =item field_get_dep_type($field)
  526. Return the type of the dependency expressed by the given field. Can
  527. either be "normal" for a real dependency field (Pre-Depends, Depends, ...)
  528. or "union" for other relation fields sharing the same syntax (Conflicts,
  529. Breaks, ...). Returns undef for fields which are not dependencies.
  530. =cut
  531. sub field_get_dep_type($) {
  532. my $field = field_capitalize(shift);
  533. return unless field_is_official($field);
  534. return $FIELDS{$field}{dependency} if exists $FIELDS{$field}{dependency};
  535. return;
  536. }
  537. =item field_get_sep_type($field)
  538. Return the type of the field value separator. Can be one of FIELD_SEP_UNKNOWN,
  539. FIELD_SEP_SPACE, FIELD_SEP_COMMA or FIELD_SEP_LINE.
  540. =cut
  541. sub field_get_sep_type($) {
  542. my $field = field_capitalize(shift);
  543. return $FIELDS{$field}{separator} if exists $FIELDS{$field}{separator};
  544. return FIELD_SEP_UNKNOWN;
  545. }
  546. =item field_register($field, $allowed_types, %opts)
  547. Register a new field as being allowed in control information of specified
  548. types. %opts is optional
  549. =cut
  550. sub field_register($$;@) {
  551. my ($field, $types, %opts) = @_;
  552. $field = field_capitalize($field);
  553. $FIELDS{$field} = {
  554. allowed => $types,
  555. %opts
  556. };
  557. }
  558. =item field_insert_after($type, $ref, @fields)
  559. Place field after another one ($ref) in output of control information of
  560. type $type.
  561. =cut
  562. sub field_insert_after($$@) {
  563. my ($type, $field, @fields) = @_;
  564. return 0 if not exists $FIELD_ORDER{$type};
  565. ($field, @fields) = map { field_capitalize($_) } ($field, @fields);
  566. @{$FIELD_ORDER{$type}} = map {
  567. ($_ eq $field) ? ($_, @fields) : $_
  568. } @{$FIELD_ORDER{$type}};
  569. return 1;
  570. }
  571. =item field_insert_before($type, $ref, @fields)
  572. Place field before another one ($ref) in output of control information of
  573. type $type.
  574. =cut
  575. sub field_insert_before($$@) {
  576. my ($type, $field, @fields) = @_;
  577. return 0 if not exists $FIELD_ORDER{$type};
  578. ($field, @fields) = map { field_capitalize($_) } ($field, @fields);
  579. @{$FIELD_ORDER{$type}} = map {
  580. ($_ eq $field) ? (@fields, $_) : $_
  581. } @{$FIELD_ORDER{$type}};
  582. return 1;
  583. }
  584. =back
  585. =head1 CHANGES
  586. =head2 Version 1.00
  587. Mark the module as public.
  588. =head1 AUTHOR
  589. Raphaël Hertzog <hertzog@debian.org>.
  590. =cut
  591. 1;