source: trunk/test/commandline_test.cc @ 2352

Last change on this file since 2352 was 2352, checked in by Peter, 11 years ago

fixes #645. error message is now: invalid argument --bar'

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.6 KB
Line 
1// $Id: commandline_test.cc 2352 2010-11-27 00:09:14Z peter $
2
3/*
4  Copyright (C) 2007, 2008, 2009, 2010 Jari Häkkinen, Peter Johansson
5
6  This file is part of the yat library, http://dev.thep.lu.se/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with yat. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Suite.h"
23
24#include "yat/utility/CommandLine.h"
25#include "yat/utility/FileUtil.h"
26#include "yat/utility/OptionArg.h"
27#include "yat/utility/OptionFile.h"
28#include "yat/utility/OptionHelp.h"
29#include "yat/utility/OptionSwitch.h"
30
31#include <cassert>
32#include <fstream>
33#include <stdexcept>
34#include <string>
35
36#include <string.h>
37
38using namespace theplu;
39using namespace yat::utility;
40bool cmd_help(yat::test::Suite& error);
41char** stradup(const char* str[], int size);
42void strafree(char** str, int size);
43bool test_switch(yat::test::Suite& error);
44bool test_arg(yat::test::Suite& error);
45void test_exception_msg(yat::test::Suite& error);
46bool test_file(yat::test::Suite& error);
47bool test_file2(yat::test::Suite& error);
48bool test_file3(yat::test::Suite& error);
49bool test_file3_(yat::test::Suite& error, const std::string&);
50bool test_file4(yat::test::Suite& error);
51bool test_file4_(yat::test::Suite& error, const std::string&);
52bool test_failures(yat::test::Suite& error);
53bool test_option_name_clash(yat::test::Suite& suite);
54bool test_free_arg(yat::test::Suite& suite);
55
56int main(int argc, char* argv[])
57{ 
58  yat::test::Suite suite(argc, argv);
59
60  suite.err() << "testing commandline" << std::endl;
61
62  // Peter, creation of this directory should perhaps be in a more central place
63  FileUtil dir("testSubDir");
64  if (!dir.exists())
65    if (mkdir(dir.path().c_str(), 0755)) {
66      suite.err() << "mkdir " << dir.path() << " failed\n";
67      return 1;
68    }
69  FileUtil subdir("testSubDir/commandline_test.dir");
70  if (!subdir.exists()) {
71    if (mkdir(subdir.path().c_str(), 0755)) {
72      suite.err() << "mkdir " << subdir.path() << " failed\n";
73      return 1;
74    }
75  }
76  if (subdir.permissions("w")) {
77    chmod(subdir.path().c_str(), S_IREAD | S_IWRITE | S_IEXEC);
78  }
79
80  try {
81    suite.add(cmd_help(suite));
82    suite.add(test_switch(suite));
83    suite.add(test_arg(suite));
84    suite.add(test_file(suite));
85    suite.add(test_file2(suite));
86    suite.add(test_file3(suite));
87    suite.add(test_file4(suite));
88    suite.add(test_failures(suite));
89    suite.add(test_option_name_clash(suite));
90    suite.add(test_free_arg(suite));
91    test_exception_msg(suite);
92  }
93  catch (std::runtime_error& e) {
94    suite.err() << "Error: unexpected exception thrown\n" << e.what() 
95                << std::endl;
96    suite.add(false);
97  }
98
99  CommandLine cmd;
100  OptionFile file(cmd, "f,file", "description");
101
102  return suite.return_value();
103}
104
105
106bool cmd_help(yat::test::Suite& suite)
107{
108  using namespace theplu::yat::utility;
109  CommandLine cmd;
110  OptionArg<std::string> dir(cmd, "d,dir", "output directory");
111  OptionHelp help(cmd);
112  OptionArg<std::string> target(cmd, "T,target", "treat DEST as a normal file", 
113                                true);
114  target.print_arg("=TARGET");
115  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done");
116  OptionSwitch version(cmd, "version", "output version and exit");
117
118  suite.err() << cmd;
119  return true;
120}
121
122
123char** stradup(const char** str, int size)
124{
125  char** res = new char*[size];
126  for (int i = 0; i<size; ++i) {
127    res[i] = strdup(str[i]);
128    assert(res[i]);
129  }
130  return res;
131}
132
133
134void strafree(char** str, int size)
135{
136  for (int i = 0; i<size; ++i) {
137    free(str[i]);
138  }
139}
140
141
142void test_exception_msg(yat::test::Suite& suite)
143{
144  // test for ticket 508
145  using namespace theplu::yat::utility;
146  CommandLine cmd;
147  OptionHelp help(cmd, "h,help", "");
148  OptionFile indata(cmd, "i,in", "input file", true, true,"r");
149  OptionSwitch cmd_memory(cmd, "m", "transpose in a memory cheap manner");
150  OptionArg<size_t> cmd_n(cmd, "n", "number of rows to print in each iteration");
151  OptionSwitch cmd_numeric(cmd, "numeric", 
152                                         "input is a numeric matrix");
153  OptionFile outdata(cmd, "o,out", "output file",true, false,"w");
154  OptionSwitch verbose(cmd, "v,verbose", "display progress");
155  int ac = 2;
156  const char* cav[] = { "test_prog", "--haha" };
157  char** av = stradup(cav, ac);
158  try {
159    cmd.parse(ac,av);
160  }
161  catch (std::runtime_error& e) {
162    std::string msg(e.what());
163    if (msg.size()<15) {
164      suite.xadd(false);
165      suite.err() << "Error: short exception message\n" 
166                  << "  exception message is: `" << msg
167                  << "' that is " << msg.size() << " characters long.\n" 
168                  << "  expected at least 15 characters\n";
169    }
170  }
171  strafree(av, ac);
172}
173
174
175bool test_switch(yat::test::Suite& suite)
176{
177  bool ok=true;
178  CommandLine cmd;
179  OptionSwitch target(cmd, "T,target", "treat DEST as a normal file", true);
180  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done", true);
181
182  suite.err() << "Testing OptionSwitch -T...";
183  {
184    int ac = 2;
185    const char* cav[] = { "test_prog", "-T" };
186    char** av = stradup(cav, ac);
187    cmd.parse(ac,av);
188    if (target.present() && !verbose.present())
189      suite.err() << "ok\n";
190    else {
191      suite.err() << "failed\n";
192      ok =false;
193    }
194    strafree(av, ac);
195  }
196
197
198  suite.err() << "Testing OptionSwitch --target...";
199  {
200    int ac = 2;
201    const char* cav[] = { "test_prog", "--target" };
202    char** av = stradup(cav, ac);
203    cmd.parse(ac,av);
204    if (target.present() && target.value() && !verbose.present())
205      suite.err() << "ok\n";
206    else {
207      suite.err() << "failed\n";
208      ok =false;
209    }
210    strafree(av, ac);
211  }
212
213  suite.err() << "Testing OptionSwitch -T -v...";
214  {
215    int ac = 3;
216    const char* cav[] = { "test_prog", "-T" , "-v"};
217    char** av = stradup(cav, ac);
218    cmd.parse(ac,av);
219    if (target.present() && verbose.present())
220      suite.err() << "ok\n";
221    else {
222      suite.err() << "failed\n";
223      ok =false;
224    }
225    strafree(av, ac);
226  }
227
228  suite.err() << "Testing OptionSwitch -vT...";
229  {
230    int ac = 2;
231    const char* cav[] = { "test_prog", "-vT"};
232    char** av = stradup(cav, ac);
233    cmd.parse(ac,av);
234    if (target.present() && verbose.present())
235      suite.err() << "ok\n";
236    else {
237      suite.err() << "failed\n";
238      ok =false;
239    }
240    strafree(av, ac);
241  }
242
243  suite.err() << "Testing OptionSwitch --no-target...";
244  {
245    int ac = 2;
246    const char* cav[] = { "test_prog", "--no-target" };
247    char** av = stradup(cav, ac);
248    cmd.parse(ac,av);
249    if (target.present() && !target.value())
250      suite.err() << "ok\n";
251    else {
252      suite.err() << "failed\n";
253      if (!target.present())
254        suite.err() << "target.present() returned false\n";
255      if (target.value())
256        suite.err() << "target.value() returned true\n";
257      ok =false;
258    }
259    strafree(av, ac);
260  }
261  return ok;
262}
263
264
265bool test_arg(yat::test::Suite& suite)
266{
267  bool ok=true;
268  CommandLine cmd;
269  OptionArg<std::string> input(cmd, "i,input", "input file");
270  OptionArg<unsigned int> n(cmd, "n", "number of lines");
271  OptionArg<double> x(cmd, "x,extra", "a float number");
272
273  suite.err() << "Testing OptionArg existence -i file...";
274  {
275    int ac = 3;
276    const char* cav[] = { "test_prog", "-i", "file" };
277    char** av = stradup(cav, ac);
278    cmd.parse(ac,av);
279    if (input.present())
280      suite.err() << "ok\n";
281    else {
282      suite.err() << "failed\n";
283      ok =false;
284    }
285    strafree(av, ac);
286  }
287
288  suite.err() << "Testing OptionArg value -i file...";
289  {
290    int ac = 3;
291    const char* cav[] = { "test_prog", "-i", "file" };
292    char** av = stradup(cav, ac);
293    cmd.parse(ac,av);
294    if (input.value()=="file")
295      suite.err() << "ok\n";
296    else {
297      suite.err() << "failed\n";
298      ok =false;
299    }
300    strafree(av, ac);
301  }
302
303  suite.err() << "Testing OptionArg existence --input file...";
304  {
305    int ac = 3;
306    const char* cav[] = { "test_prog", "--input", "file" };
307    char** av = stradup(cav, ac);
308    cmd.parse(ac,av);
309    if (input.present())
310      suite.err() << "ok\n";
311    else {
312      suite.err() << "failed\n";
313      ok =false;
314    }
315    strafree(av, ac);
316  }
317
318  suite.err() << "Testing OptionArg value --input=file...";
319  {
320    int ac = 2;
321    const char* cav[] = { "test_prog", "--input=file" };
322    char** av = stradup(cav, ac);
323    cmd.parse(ac,av);
324    if (input.value()=="file")
325      suite.err() << "ok\n";
326    else {
327      suite.err() << "failed\n";
328      ok =false;
329    }
330    strafree(av, ac);
331  }
332
333  suite.err() << "Testing OptionArg value --input=\"file called something\"...";
334  {
335    int ac = 2;
336    const char* cav[] = { "test_prog", "--input=\"file called something\"" };
337    char** av = stradup(cav, ac);
338    cmd.parse(ac,av);
339    if (input.value()=="file called something")
340      suite.err() << "ok\n";
341    else {
342      suite.err() << "failed\n";
343      suite.err() << "value is `" << input.value() << "'\n"
344            << "expected `file called something'\n";
345      ok =false;
346    }
347    strafree(av, ac);
348  }
349
350  suite.err() << "Testing OptionArg unsigned int value -n 3...";
351  {
352    int ac = 3;
353    const char* cav[] = { "test_prog", "-n", "3" };
354    char** av = stradup(cav, ac);
355    cmd.parse(ac,av);
356    if (n.value()==3)
357      suite.err() << "ok\n";
358    else {
359      suite.err() << "failed\n";
360      ok =false;
361    }
362    strafree(av, ac);
363  }
364
365
366  suite.err() << "Testing OptionArg 2 value --input file -n 3...";
367  {
368    int ac = 5;
369    const char* cav[] = { "test_prog", "--input", "file", "-n", "3" };
370    char** av = stradup(cav, ac);
371    cmd.parse(ac,av);
372    if (input.value()=="file")
373      suite.err() << "ok\n";
374    else {
375      suite.err() << "failed\n";
376      ok =false;
377    }
378    strafree(av, ac);
379  }
380
381  suite.err() << "Testing OptionArg double value -x -6...";
382  try {
383    int ac = 3;
384    const char* cav[] = { "test_prog", "-x", "-6" };
385    char** av = stradup(cav, ac);
386    cmd.parse(ac,av);
387    if (x.value()==-6)
388      suite.err() << "ok\n";
389    else {
390      suite.err() << "failed\n";
391      ok =false;
392    }
393    strafree(av, ac);
394  }
395  catch (std::runtime_error& e) {
396    ok = false;
397    suite.err() << "failed\nexception thrown with what(): " << e.what() << "\n";
398  }
399
400  suite.err() << "Testing OptionArg double value --extra -6...";
401  try {
402    int ac = 3;
403    const char* cav[] = { "test_prog", "--extra", "-6" };
404    char** av = stradup(cav, ac);
405    cmd.parse(ac,av);
406    if (x.value()==-6)
407      suite.err() << "ok\n";
408    else {
409      suite.err() << "failed\n";
410      ok =false;
411    }
412    strafree(av, ac);
413  }
414  catch (std::runtime_error& e) {
415    ok=false;
416    suite.err() << "failed\nexception thrown with what(): " << e.what() << "\n";
417  }
418
419  suite.err() << "Testing OptionArg::value(T) ... ";
420  try {
421    int ac = 1;
422    const char* cav[] = { "test_prog"};
423    char** av = stradup(cav, ac);
424    cmd.parse(ac,av);
425    n.value(5);
426    if (n.present()==false && n.value()==5)
427      suite.err() << "ok\n";
428    else {
429      suite.err() << "failed\n";
430      ok = false;
431    }
432    strafree(av, ac);
433  }
434  catch (std::runtime_error& e) {
435    suite.err() << "failed\n";
436    ok = false;
437  }
438
439  // test for ticket 645
440  suite.err() << "Testing error message with -n STRING\n";
441  try {
442    int ac = 3;
443    const char* cav[] = { "test_prog", "-n", "STRING"};
444    char** av = stradup(cav, ac);
445    try {
446      cmd.parse(ac,av);
447      strafree(av, ac);
448      ok=false;
449      suite.err() << "error: expected parse to throw\n"; 
450    }
451    catch (std::runtime_error& e) {
452      strafree(av, ac);
453      suite.err() << "expected exception: what(): " << e.what() << "\n";
454    }
455  }
456  catch (std::runtime_error& e) {
457    suite.err() << "failed: " << e.what() << "\n";
458    ok=false;
459  }
460  return ok;
461}
462
463bool test_failures(yat::test::Suite& suite)
464{
465  bool ok=true;
466  CommandLine cmd;
467  OptionSwitch verbose(cmd, "v,verbose", "explain what is being done");
468  OptionArg<std::string> input(cmd, "i,input", "input file");
469  OptionArg<unsigned int> n(cmd, "n", "number of lines");
470
471  suite.err() << "Testing unknown option --peter...";
472  {
473    int ac = 2;
474    const char* cav[] = { "test_prog", "--peter"};
475    char** av = stradup(cav, ac);
476    try{
477      cmd.parse(ac,av);
478      suite.err() << "failed\n";
479      ok =false;
480    }
481    catch (...) {
482      suite.err() << "ok\n";
483    }
484    strafree(av, ac);
485  }
486
487  suite.err() << "Testing unknown option -jvjhsgad...";
488  {
489    int ac = 2;
490    const char* cav[] = { "test_prog", "-vjhsgad"};
491    char** av = stradup(cav, ac);
492    try{
493      cmd.parse(ac,av);
494      suite.err() << "failed\n";
495      ok =false;
496    }
497    catch (...) {
498      suite.err() << "ok\n";
499    }
500    strafree(av, ac);
501  }
502
503
504  suite.err() << "Testing invalid option -nv 3...";
505  {
506    int ac = 3;
507    const char* cav[] = { "test_prog", "-nv", "3"};
508    char** av = stradup(cav, ac);
509    try{
510      cmd.parse(ac,av);
511      suite.err() << "failed\n";
512      ok =false;
513    }
514    catch (...) {
515      suite.err() << "ok\n";
516    }
517    strafree(av, ac);
518  }
519
520
521  suite.err() << "Testing 23.12 is not unsigned int...";
522  {
523    int ac = 3;
524    const char* cav[] = { "test_prog", "-n", "23.12"};
525    char** av = stradup(cav, ac);
526    try{
527      cmd.parse(ac,av);
528      suite.err() << "failed\n";
529      ok =false;
530    }
531    catch (std::runtime_error& e) {
532      suite.err() << "ok\n";
533    }
534    strafree(av, ac);
535  }
536
537  suite.err() << "Testing -1 is not unsigned int...";
538  {
539    int ac = 3;
540    const char* cav[] = { "test_prog", "-n" "-1"};
541    char** av = stradup(cav, ac);
542    try{
543      cmd.parse(ac,av);
544      suite.err() << "failed\n";
545      ok =false;
546    }
547    catch (...) {
548      suite.err() << "ok\n";
549    }
550    strafree(av, ac);
551  }
552
553
554  suite.err() << "Testing invalid: test_prog peter...";
555  {
556    int ac = 2;
557    const char* cav[] = { "test_prog", "peter" };
558    char** av = stradup(cav, ac);
559    try{
560      cmd.parse(ac,av);
561      suite.err() << "failed\n";
562      ok =false;
563    }
564    catch (...) {
565      suite.err() << "ok\n";
566    }
567    strafree(av, ac);
568  }
569
570  suite.err() << "Testing OptionArg required ...";
571  {
572    OptionArg<std::string> required(cmd, "required", "required", true); 
573    int ac = 1;
574    const char* cav[] = { "test_prog" };
575    char** av = stradup(cav, ac);
576    try{
577      cmd.parse(ac,av);
578      suite.err() << "failed\n";
579      ok =false;
580    }
581    catch (...) {
582      suite.err() << "ok\n";
583    }
584    strafree(av, ac);
585  }
586
587
588  return ok;
589}
590
591
592bool test_file(yat::test::Suite& suite)
593{
594  bool ok=true;
595  CommandLine cmd;
596  OptionFile inclones(cmd, "clones", "file containing clones");
597  OptionFile indata(cmd, "data", "data to merge");
598  OptionFile out(cmd, "o,out", "data to merge", true, false, "w");
599  OptionSwitch help(cmd, "h,help", "display this help and exit");
600
601  suite.err() << "Testing OptionFile... ";
602  {
603    int ac = 7;
604    const char* cav[] = { "test_prog", "--clones", "commandline_test.cc", 
605                          "--data", "commandline_test.cc", "-o", 
606                          "commandline_test.cc"};
607    char** av = stradup(cav, ac);
608    cmd.parse(ac,av);
609    suite.err() << "ok\n";
610    strafree(av, ac);
611  }
612  return ok;
613}
614
615
616bool test_file2(yat::test::Suite& suite)
617{
618  suite.err() << "Testing OptionFile in write-protected directory... ";
619
620  if (yat::test::run_as_root()) {
621    suite.err() << "skipped because user is root\n";
622    // skipping means test should still be successful
623    return true;
624  }
625
626  FileUtil subdir("testSubDir/commandline_test.dir/write-protected");
627  if (!subdir.exists()) {
628    if (mkdir(subdir.path().c_str(), 0555)) {
629      suite.err() << "mkdir " << subdir.path() << " failed\n";
630      return false;
631    }
632  }
633  else
634    if (!subdir.permissions("w")) {
635      suite.err() << subdir.path() << " already exists\n";
636      return false;
637    }
638
639  FileUtil file("testSubDir/commandline_test.dir/write-protected/out.txt");
640  if (file.exists()) {
641    suite.err() << "FileUtil::exists returns true unexpectedly\n";
642    return false;
643  }
644  if (file.permissions("w")==0) {
645    suite.err() << "FileUtil::permission(\"w\") returns 0 while "
646                << "-1 was expected\n";
647    return false;
648  }
649
650  bool ok=true;
651  CommandLine cmd;
652  OptionFile out(cmd, "o,out", "output to file", false, false, "w");
653  OptionSwitch help(cmd, "h,help", "display this help and exit");
654
655  {
656    int ac = 3;
657    const char* cav[] = { "test_prog", "--out", 
658                    "testSubDir/commandline_test.dir/write-protected/out.txt"};
659    char** av = stradup(cav, ac);
660    try {
661      cmd.parse(ac,av);
662      ok =false;
663      suite.err() << "failed\n";
664    }
665    catch (cmd_error& e) {
666      suite.err() << "ok\n";
667      suite.err() << "catch expected error: " << e.what() << "\n";
668    }
669    strafree(av, ac);
670  }
671  return ok;
672}
673
674
675bool test_file3(yat::test::Suite& suite)
676{
677  suite.err() << "Testing OptionFile in non-existing tree\n";
678  // testing error message from OptionFile when tree is not existing
679  bool ok=true;
680  ok &= test_file3_(suite, "r");
681  ok &= test_file3_(suite, "w");
682  ok &= test_file3_(suite, "x");
683  ok &= test_file3_(suite, "d");
684  return ok;
685}
686
687
688bool test_file3_(yat::test::Suite& suite, const std::string& perm)
689{
690  CommandLine cmd;
691  OptionFile file(cmd, "file", "", true, false, perm);
692
693  suite.err() << "Testing OptionFile '" << perm << "' ... "; 
694  int ac = 3;
695  const char* cav[] = { "test_prog", "--file", "sjhgaw/jmegb/tmp.tmpx"};
696  char** av = stradup(cav, ac);
697  try {
698    cmd.parse(ac,av);
699    suite.err() << "no\n";
700    strafree(av, ac);
701    return false;
702  }
703  catch (cmd_error& e) {
704    suite.err() << "ok\n";
705    suite.err() << "catch expected error: " << e.what() << "\n";
706  }
707  strafree(av, ac);
708  return true;
709}
710
711
712bool test_file4(yat::test::Suite& suite)
713{
714  FileUtil file("testSubDir/commandline_test.dir/test_file4.txt");
715  if (!file.exists()) {
716    std::ofstream os(file.path().c_str());
717  } 
718  chmod(file.path().c_str(), 0);
719
720  suite.err() << "Testing OptionFile with no permssions\n";
721  bool ok=true;
722  ok &= test_file4_(suite, "r");
723  ok &= test_file4_(suite, "w");
724  ok &= test_file4_(suite, "x");
725  ok &= test_file4_(suite, "d");
726  return ok;
727}
728
729
730bool test_file4_(yat::test::Suite& suite, const std::string& perm)
731{
732  CommandLine cmd;
733  OptionFile file(cmd, "file", "", true, false, perm);
734
735  suite.err() << "Testing OptionFile '" << perm << "' ... "; 
736  try {
737    int ac = 3;
738    const char* cav[] = { "test_prog", "--file", 
739                          "testSubDir/commandline_test.dir/test_file4.txt"};
740    char** av = stradup(cav, ac);
741    cmd.parse(ac,av);
742    suite.err() << "no\n";
743    strafree(av, ac);
744    return false;
745  }
746  catch (cmd_error& e) {
747    suite.err() << "ok\n";
748    suite.err() << "catch expected error: " << e.what() << "\n";
749  }
750  return true;
751}
752
753
754bool test_option_name_clash(yat::test::Suite& suite)
755{
756  bool ok=true;
757  suite.err() << "Testing long option name clash ...";
758  try {
759    CommandLine cmd;
760    OptionSwitch op1(cmd, "opt", "bla bla");
761    OptionSwitch op2(cmd, "o,opt", "other bla");
762    ok=false;
763    suite.err() << "failed\n";
764  }
765  catch (std::runtime_error& e) {
766    suite.err() << "ok\n";
767  }
768  suite.err() << "Testing short option name clash ...";
769  try {
770    CommandLine cmd;
771    OptionSwitch op1(cmd, "o", "bla bla");
772    OptionSwitch op2(cmd, "o,opt", "other bla");
773    ok=false;
774    suite.err() << "failed\n";
775  }
776  catch (std::runtime_error& e) {
777    suite.err() << "ok\n";
778  }
779
780  return ok;
781}
782
783
784bool test_free_arg(yat::test::Suite& suite)
785{
786  bool ok=true;
787  suite.err() << "Testing free arguments ...";
788
789  CommandLine cmd;
790  cmd.allow_free_args(2);
791  OptionHelp help(cmd);
792  int ac = 3;
793  const char* cav[] = { "test_prog", "file", "kl"};
794  char** av = stradup(cav, ac);
795  cmd.parse(ac, av);
796  suite.err() << "ok\n";
797  strafree(av, ac);
798  return ok;
799}
800
801
802
Note: See TracBrowser for help on using the repository browser.