% file: ctan_chk.w
%
\def\Tex{\TeX}
\def\cweb{\Cweb}
\def\Cweb{{\prgstyle Cweb}}
\def\prgstyle{\tt \sl }
\def\NOsign{
 {\tt{\char`\#}}
}
\def\Verticalbar{{\tt \char`|}}
\def\GTsign{
\ifmmode
 >
\else
$>$
\fi
}
\def\Arrow{$\Rightarrow$}
\def\prtobrace{$\{$}
\def\prtcbrace{$\}$}
\def\Backslash{
{\tt\char`\\}
}

\def\printlistinglineno{\hskip .7 in \llap{\the\lineno:\quad}}
\def\ptindent#1{\line{\hskip.5in{#1}\hfill}}
\def\Yacco2{Ya$c_2o_2$}
\def\yacco2{\Yacco2}
\def\O2{$O_2$}
\def\o2{\O2}
\def\Cpp{C\kern-.25em \raise.25ex\hbox{\tt $+\kern-0.2ex+$}}
\def\Olinker{$O_{2}^{linker}$}
\def\olinker{$O_{2}^{linker}$}
\def\TILDE{\catcode`\~=11{}~}
\def\INDENT#1#2{\line{\hskip#1{#2}\hfill}}
\def\fbreak{\hfill\break}


@* Gawk program |ctan_chk.gawk|.\fbreak
Basic Gawk program that uses Ctan's published guidelines for authors to help eliminate slopiness in uploaded files/project.
It is completely open for users to program additional guidelines and Ctan's future  adjustments. 
The program came about when I first attempted to upload ``Yacco2'' for Ctan consideration.
As Yacco2 was quite large, it took me 3 attempts to clean up my project.
Depending on how u develop your project, in my case the Yacco2 project for Ctan upload is a subset of the complete system
and so each uplift required the guideline assessment/purging process.

This is my attempt to help both the author in getting the new system in shape for Ctan uplift 
and to lower the Ctan volanteers interaction to aid for publishing on their servers.
It is my thank you to these volanteers / Ctan.
\fbreak
\fbreak
This |gawk| program verifies whether an upload project for CTAN 
follows its published guidelines on their website:\fbreak
\ptindent{http://ctan.org/upload/}
\fbreak
Here is the link to the awk/gawk reference manual for people needing a refresher to its programming statements:\fbreak
\ptindent{https://www.gnu.org/software/gawk/manual/gawk.html\#Reading-Files}

@*1 License.\fbreak
ctan\_chk's distributed source code is subject to the terms of the GNU General Public License (version 3).
If a copy of the MPL was not distributed with this file, you can obtain one at https://gnu.org/licenses/gpl.html.
\fbreak
\fbreak
\ptindent{Project:                   ctan guidelines verifier and corrector program for uploading projects}
\ptindent{Distributed under license: GNU General Public License (version 3).}
\ptindent{Distribution Date:         \today}
\ptindent{Distribution version:      1.0}
\ptindent{Comments:                  Currently for the Unix flavoured Platforms running Gawk}
\ptindent{Author:                    Dave Bone}
\fbreak
\ptindent{Contributors list:}
\ptindent{  Dave Bone}

@*2 |Ctan_chk| reference.\fbreak
Unzip the |ctan_chk.zip| file.
Please read |ctan_chk.pdf| document. It instructs one in ``how to'' use the gawk |ctan_chk.gawk| program.

@*2  Literate Programming genre.\fbreak
|ctan_chk.pdf| user manual and |ctan_chk.gawk| program are generated by the Cweb system's 
{\it{cweave}} and {\it{ctangle}} programs along with the {\it{pdftex}}.
The |ctan_chk_bash| script does it all for u; have a read it doesn't bite.
Please consider using Cweb and joining
``www.tug.org'' where u'll find the Cweb system.

@*1 Comments on program's functions.\fbreak
Normally u edit the |ctan_chk.gawk| file (using gawk comments) as to what "verification function" is called to check out your project's files.
Here is a list of the verification functions to call:\fbreak
Helper functions:\fbreak
\ptindent{|is_file_a_directory| --- is file a directory type rather than a data type?}
\ptindent{|is_file_an_executable| --- Maybe too platform dependent: is it an executable}
\fbreak
Verification functions:\fbreak
\ptindent{|chk_auxiliary_files| --- files that should be removed / deleted}
\ptindent{|chk_file_permissions| --- file execute permissions check}
\ptindent{|chk_extended_file_attributes| --- does file have  extended attribute like @@}
\ptindent{|chk_empty_files| --- zero byte size file?}
\ptindent{|chk_empty_directory| --- empty folder}
\ptindent{|chk_file_to_bypass_in_zip| --- file to bypass by zip using its -x option}
\fbreak
Correction functions:\fbreak
\ptindent{|remove_file_s_execute_attribute| --- Read ``Remove file's execute attribute'' section for details}
\ptindent{|delete_file| --- interacts with user. Used by itself or from other functions like |chk_auxiliary_files|}
\ptindent{|remove_file_s_extended_attributes| --- Remove extended attribute from file (platform dependent)}

@*2 Running Gawk program has 2 run/pass attitude.\fbreak
U run this program twice with appropriate editing sessions inbetween the run passes:\fbreak
\ptindent{run Pass 1 function where your edited functions to call and capturing output with {\it{tee}} utility}
\ptindent{\Arrow{} pass 1's input file is an absolute pathed files list. See |How to use this gawk program| section}
\ptindent{\Arrow{} assess the messages outputted as to what guidelines need to be corrected}
\ptindent{\Arrow{} outputted messages have 2 parts: part 1 the filename and part 2 the quoted message}
\fbreak
\ptindent{run Pass 2 function where u comment out pass 1 call and uncomment pass 2 function call}
\ptindent{\Arrow{} inside the |pass2_correct| function, uncomment the appropriate correction function to call}
\ptindent{\Arrow{} the captured messages from {\it{tee}} of pass 1 is its inputted file}
\ptindent{\Arrow{} in awk/gawk terms this |gawk|'s record is composed of fields where the field separator is space}
\ptindent{\Arrow{} so the 2nd pass receives the 2 fields filename, and message}
\fbreak
\fbreak
Output example of guideline violations from Pass 1:\fbreak
\ptindent{\Arrow{} "/yacco2/.DS\_Store" 'Extended attributes -rwxr-xr-x@@'}
\ptindent{\Arrow{} "/yacco2/.DS\_Store" 'Write permissions -rwxr-xr-x@@ to possibly delete file type: data'}
\ptindent{\Arrow{} "/yacco2/.DS\_Store" 'Bypass file in zip'}
\ptindent{\Arrow{} "/yacco2/.gitignore" 'Auxilary file to be deleted'}
\ptindent{\Arrow{} "/yacco2/.nbattrs" 'Extended attributes -rwxr-xr-x+'}
\ptindent{\Arrow{} "/yacco2/.nbattrs" 'Write permissions -rwxr-xr-x+ to possibly delete file type: XML'}
\ptindent{\Arrow{} "/yacco2/.nbattrs" 'Bypass file in zip'}
\ptindent{\Arrow{} "/yacco2/bin/.DS\_Store" 'Extended attributes -rwxr-xr-x@@'}
\ptindent{\Arrow{} "/yacco2/bin/.DS\_Store" 'Write permissions -rwxr-xr-x@@ to possibly delete file type: data'}
\ptindent{\Arrow{} "/yacco2/bin/.DS\_Store" 'Bypass file in zip'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/1lrerrors.log" 'Auxilary file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/1lrerrors.log" 'Empty file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/1lrtracings.log" 'Auxilary file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/1lrtracings.log" 'Empty file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/o2.man" 'Extended attributes -rw-r--r--@@'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/o2linker.man" 'Extended attributes -rw-r--r--@@'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/yacco2.man" 'Extended attributes -rw-r--r--@@'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/yacco2cmd.tmp" 'Auxilary file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bin/man/man1/yacco2cmd.tmp" 'Empty file to be deleted'}
\ptindent{\Arrow{} "/yacco2/bld\_bash\_APPLE" 'Extended attributes -rwxr-xr-x@@'}
\ptindent{\Arrow{} "/yacco2/bld\_bash\_APPLE" 'Write permissions -rwxr-xr-x@@ to possibly delete file type: ASCII'}
\ptindent{\Arrow{} "/yacco2/book/appendix\_a.aux" 'Auxilary file to be deleted'}
\ptindent{\Arrow{} "/yacco2/book/ch\_fsm.tex" 'Write permissions -rwxr-xr-x@@ to possibly delete file type: LaTeX'}
\fbreak
Running the initial program could potentially output the above sampling.
If there are just 1 message type outputted then u would just focus on ``pass 2'' to correct it.
Having a mix of messages means ``pass 1'' should be edited to just deal with the 1 message type
 at a time. This allows the homogenous output to be captured and edit the removal of  files to bypass.
Now the program can be edited to support the message type action correcting the violation
and rerun.
Each listed guideline type would go thru this edit behaviour:  ``pass 1'' to see the violations, analyse its outcome,
re-edit program, and then run the correction.  

@*2 Anatomy of this |gawk| program.\fbreak
It contains 3 |gawk| actions: BEGIN, Body, and END.
This program's BEGIN and END actions are just read record stats.
U can add your own code as this program is open to your creativity.
The action Body contains the 2 passes: |pass1_guidelines_verify| and |pass2_correct|.
To comment out a function call, add a \NOsign{} at the beginning of its line.
To activate a commented out function call, just remove its |gawk|'s comment character: \NOsign.

@*2 How to generate the  pdf document and this gawk program.\fbreak
The \Cweb{} ``literate programming'' framework is used to generate
its pdf document and its gawk program from |ctan_chk.w|.
Though Cweb emits a ``c'' type code, gawk code is very similar to ``c''.\fbreak
0) Run from a terminal using bash.\fbreak
\ptindent{{\bf{. ctan\_chk\_bash}}}
\ptindent{\Arrow{} The various utilities used are outputed on the terminal}

U are open to add your own code to the |ctan_chk.w| program and rerun the above script.
If u do not have the \Cweb{} framework installed, u can
add the code to the |ctan_chk.gawk| file. 

@*2 How to use this gawk program.\fbreak
0) Run from a terminal using bash.\fbreak
1) Generate a file containing your project's files whose path is absolute\fbreak
\ptindent{{\bf{find /absolute path of your project \GTsign{} xxx}}}
\ptindent{\Arrow{} xxx is a holding file containing your project's files} 
\ptindent{\Arrow{} example of an absolute path: {\bf {/usr/local/yacco2}}} 
2) Edit |ctan_chk.gawk| to what function calls u want to use inside |pass1_guidelines_verify|\fbreak
3) Run gawk ctan\_chk program verifying your project\fbreak
\ptindent{{\bf{gawk -f ctan\_chk.gawk xxx}} \NOsign xxx is the file read containing the files to assess}\fbreak
\ptindent{\Arrow{} it outputs files to correct on the terminal with appropriate guideline message}
\ptindent{\Arrow{} no outputted messages means your project passed with flying colours :\prtcbrace}
\fbreak
\ptindent{\Arrow{} To capture the verification output:}
\ptindent{{\bf{gawk -f ctan\_chk.gawk xxx\Verticalbar{}tee yyy}}}\fbreak
\ptindent{\Arrow{} Use of {\it{tee}} utility to capture the output into yyy file}

@*3 Example: Checking auxilary files to delete.\fbreak
Here are the steps to see whether there are files to remove/delete.
File xxx contains the files to verify as exampled earlier in this document.\fbreak
1) {\bf{gawk -f ctan\_chk.gawk xxx}}\fbreak
\fbreak
2) Its output should have messages similar to this:\fbreak
\ptindent{\Arrow{} "/yacco2/bin/man/man1/1lrerrors.log" 'Auxilary file to be deleted'}
\fbreak
3) Rerun {\bf{gawk -f ctan\_chk.gawk xxx\Verticalbar{}tee yyy}} where the output messages are put in {\bf{yyy}} file.\fbreak
\break
4) Edit: comment out  pass1\_guidelines\_verify and uncomment \#pass2\_correct in Body action code:\fbreak
The gened |ctan_chk.gawk| program could have different commented ``section no:'' used in the below
edit session. What is important are function names referenced: for example, |pass1_guidelines_verify|  which
you'll find in your |ctan_chk.gawk| program. Same comments apply against the other pieces of code being edited.\fbreak
\ptindent{\# section no:22*/}
\ptindent{\# section no28:*/}
\ptindent{\prtobrace}
\ptindent{ pass1\_guidelines\_verify(\$1);}
\ptindent{ \#pass2\_correct(\$1,\$2);}
\ptindent{\prtcbrace}
to\fbreak
\ptindent{\# section no:22*/}
\ptindent{\# section no28:*/}
\ptindent{\prtobrace}
\ptindent{ \#pass1\_guidelines\_verify(\$1);}
\ptindent{ pass2\_correct(\$1,\$2);}
\ptindent{\prtcbrace}
\fbreak
5) Edit: uncomment out \#delete\_file in pass2\_correct:\fbreak
\ptindent{\# section no:28*/}
\ptindent{\# section no29:*/}
\ptindent{function pass2\_correct(filename,message)}
\ptindent{\prtobrace}
\ptindent{ \#remove\_file\_s\_execute\_attribute(filename,message);}
\ptindent{ \#remove\_file\_s\_extended\_attributes(filename,message);}
\ptindent{ \#delete\_file(filename);}
\ptindent{\prtcbrace}
to\break
\ptindent{\# section no:28*/}
\ptindent{\# section no29:*/}
\ptindent{function pass2\_correct(filename,message)}
\ptindent{\prtobrace}
\ptindent{ \#remove\_file\_s\_execute\_attribute(filename,message);}
\ptindent{ \#remove\_file\_s\_extended\_attributes(filename,message);}
\ptindent{ delete\_file(filename);}
\ptindent{\prtcbrace}
\fbreak
\fbreak
\fbreak
\fbreak
\fbreak
\fbreak
6) Save edited |ctan_chk.gawk| program and rerun with {\bf{yyy}}:\fbreak
\ptindent{\Arrow{} {\bf {gawk -f ctan\_chk.gawk yyy}}}
Each file being deleted is questioned and allows u to bypass it.\fbreak
This is due to the {\bf{-i}} option used in {\it{rm -i file-to-delete}}\fbreak
\fbreak
Other guideline contraints would follow the same run / edit / rerun template above adjusting
the program accordingly.\fbreak
\ptindent{\Arrow{} {\bf{Just remember to reset the program back to its initial setting.}}}
As an aside comment, u could have uncommented the |delete_file| call inside the   
|chk_auxiliary_files| function and do the correction while in the ``assess guideline'' pass.
So why did u not express this before :\prtobrace?
Well the normal correction pattern is see what guidelines are violated by ``pass 1', edit the program, 
and then rerun against ``pass 2'' correction.
Once u are familiar with the program throw out my patterns and jig your own :\prtcbrace.
@* Function code sections.
@*2 ctan gawk's comments --- author, license etc.
@<Emit gawk comments@>=
#
# Program: ctan_chk.gawk
#
# Author:  Dave Bone
#
# License:  
# This Source Code Form is subject to the terms of the GNU General Public License (version 3). 
# If a copy of the MPL was not distributed with this file, 
# You can obtain one at:  "https://gnu.org/licenses/gpl.html".
#
# Purpose: Implementation of some suggested CTAN guidelines that an upload project should respect.
#          Correction functions help u cleanup the droppings.
# See www.ctan.org website for  "upload guideline" document
# Read ctan_chk.pdf document describing the program with various run scenarios.
#
#

@*1 Helper functions.
@*2 Is file a directory.\fbreak
Directory found returns 1.
@<|is_file_a_directory|@>=
function is_file_a_directory(filename, filetype)@\
{
 x="file \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 split(a,parts);
 filetype[1] = parts[2];
 xx = parts[2];
 str= "^directory$";
 if (xx ~ str) {
  return 1;
 }
 return 0; 
}

@*2 Is file an executable.\fbreak
This function {\bf{might be too platform dependent}}.\fbreak
If so then don't call it or find an alternative.\fbreak
A return 1 means it's an executable.
@<|is_file_an_executable|@>=
function is_file_an_executable(filename, filetype)@\
{
 x="file %s";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 split(a,parts);
 filetype[1] = parts[2];
 xx = parts[2];
 str= "(executable|POSIX|Mach-O|ELF)$";
 if (xx ~ str) {
  return 1; 
  }
  return 0;
}

@*1 Guideline assessment functions.
@*2 Check for auxiliary type files.\fbreak
``str'' contains a regular expression of file extensions to search for starting with a ``.'' followed by
the round bracket expression of extensions to search on ending by the end-of-string regular expression indicator: \$.
Inside the rounded bracket expression is the choice of extensions separated by  \Verticalbar{} 
which is the ``or'' operator of a regular expression.\fbreak
\fbreak
The double \Backslash{} in str is due to how gawk parses the program code:
it does a double pass:\fbreak
\ptindent{1) on the string: str}
\ptindent{2) on the regular expression called}
Just having a ``.'' at the start of  regular expression means it is a single ``wild character'' to accept. 
To accept a period ``.'' that starts the file extension, u have to escape it.
Pass 1 for the literal string is the first escape sequence on \Backslash{} the 2nd backslash.
In pass 2 for the regular expession called, the \Backslash{} escapes the ``.'' to not interpret
as the regular expression  wild character.\fbreak
\fbreak
str can be added to. Make sure u include the added extension started with the \Verticalbar{} when appended to before
the closing off rounded bracked ``)''. \fbreak
\fbreak
|chk_auxiliary_files| outputs a 2 part message: file name and message it considers as an auxiliary file to be deleted.
Calling |delete_file| interacts with the user whether to delete it or not.
It is commented out so that the messages can saved and reviewed before the correction pass takes place:
See |Pass 2 --- correct violated guidelines| section providing more information.
U can uncomment the |delete_file| statement below if u prefer to delete the file in the assessment pass 
rather than the correction pass. Your call and temperment. 
@<|chk_auxiliary_files|@>=
function chk_auxiliary_files(filename)@\
{
 if (is_file_a_directory(filename) == 1) 
  return 0;

 str= "\\.(ps|gitignore|git|aux|log|bbl|bcf|blg|brf|ilg|ind|idx|glo|loa|lof|lot|nav|out|snm|vrb|toc|dvi|glg|gls|tmp|o|bak|mpx|scn|toc)$";
 if (filename ~ str) {
  a= "\"%s\" 'Auxilary file to be deleted'";
  b= sprintf(a,filename);
  print b;
  #delete_file(filename);
  return 1;
 }
 return 0;
}

@*2 Check for extended attributes.\fbreak
Basicly looks at the output from the ``ls -al'' of a file.
If there are extended attributes it will be displayed at the end of the first field as ``@@'' or ``+''.
It outputs the filename and message to the terminal.
Return 1 if found.
@<|chk_extended_file_attributes|@>=
function chk_extended_file_attributes(filename)@\
{
 x="ls -al \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 number_of_fields = split(a,parts);
 if (number_of_fields < 9)
  return 0;
  
 xx=parts[1];
 str= "(@@|+)$";
 if (xx !~ str) {
  return 0;
 }
  
 a="\"%s\" 'Extended attributes %s'";   
 b=sprintf(a,filename,parts[1]);
 print b;
 #remove_file_s_extended_attributes(filename,b);
 return 1;
}
@*2 Check for empty files.\fbreak
Uncomment out the |delete_file| statement below if u want to remove it in the assessment phase.
Asks whether to delete the zero sized file and  returns 1.
@<|chk_empty_files|@>=
function chk_empty_files(filename)@\
{
 if (is_file_a_directory(filename) == 1)
  return 0;
 
 x="ls -al \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 number_of_fields = split(a,parts);
 if (number_of_fields < 9)@\
 {
  print "ERROR ===> ls -al should be 9 fields and it isn't: " a " no fields: " number_of_fields;
  return 0;
 }
 i=strtonum(parts[5]);
 if (i > 0){
  return 0;
 }
 a="\"%s\" 'Empty file to be deleted'";
   
 b=sprintf(a,filename);
 print b;
 #delete_file(filename);
 return 1;
}

@*2 Check for empty directory.\fbreak
Empty directory found returns a 1.\fbreak
This check requires u to assess what u want to do: delete it, or add an ``info.txt'' file inside it.
For example in the ``Yacco2'' project, it is a full
development framework of a compiler/compile, and its API library.
It has empty Debug folders. Its Release folders contained content.
Depending on what the user wanted to debug and link against, the empty Debug folder 
provided consistency to the framework and hence it was needed.  So an ``info.txt'' file 
was created inside each Debug folder  expressing their intent/use to the developer.

@<|chk_empty_directory|@>=
function chk_empty_directory(filename)@\
{
 if (is_file_a_directory(filename) == 0)
  return 0;
   
 x="du -sk \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 number_of_fields = split(a,parts);
 
 i=strtonum(parts[1]);
 if (i > 0)
  return 0;

 a="\"%s\" 'Empty directory to be deleted or needs to add info.txt file inside it'";
   
 b=sprintf(a,filename);
 print b;
 return 1;
}


@*2 Check file permissions.\fbreak
Bypass a directory.
If the file does not have an executable attribute then exit stage gracefully.

@<|chk_file_permissions|@>=
function chk_file_permissions(filename)@\
{
 filetype[1]="";
 if (is_file_a_directory(filename, filetype) == 1)
  return 0;
 if (is_file_an_executable(filename,filetype) == 1)
  return 0;
   
 x="ls -al \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y);
 
 number_fields = split(a,parts);
 
 str= "x";
 if (parts[1] ~ str) {
  a="\"%s\" 'Write permissions %s to possibly delete file type: %s'"; 
  b=sprintf(a,filename,parts[1],filetype[1]);
  print b;
  return 1;
  }
  return 0;
}

@*2 Check file to bypass in zip.\fbreak
This is just a check function that lists files to bypass in the zip file creation process.\fbreak
An example of creating a zip file:\fbreak
\ptindent{{\bf{zip -r -ll yacco2.zip yacco2 -x '*DS\_Store' -x '*.nbattrs'}}}
\ptindent{\Arrow{} -r recurse through the folder getting all its subfolders and their contents}
\ptindent{\Arrow{} -ll parameter reduces carriage return/line feed combo to line feed}
\ptindent{\Arrow{} -x parameter lists by regular expression the file(s) to bypass}
\ptindent{\Arrow{} The bypassed exampled files are Apple OSX specific}

@<|chk_file_to_bypass_in_zip|@>=
function chk_file_to_bypass_in_zip(filename)
{
 str= ".(DS_Store|.nbattrs)$";
 if (filename ~ str) {
  a="\"%s\" 'Bypass file in zip'";
  b=sprintf(a,filename);
  print b;
  return 1;
  }
 return 0;
}


@*1 Correct guideline violations.
@*2 Remove file's execute attribute.\fbreak
Due to security reasons, u cannot have an indirect bash script run against a list of files
to change their ownership attributes.
It will run but nothing will be changed.\fbreak
So what to do?\fbreak
\ptindent{\Arrow{} gawk -f |ctan_chk.gawk| xxx \Verticalbar{}tee yyy}
\ptindent{\Arrow{} \ \ \ \ u can use your own temporary file name instead of yyy}
\ptindent{\Arrow{} \ \ \ \ just remember to substitute your file name in place of yyy}
\ptindent{\Arrow{} where the |chk_file_permissions| function is the only function run}
\ptindent{\Arrow{} and the other functions have been commented out}
\fbreak
\ptindent{Edit yyy file containing the list of potential files, removing files keeping their execute attribute.}
\break
\ptindent{Run this below gawk script interactively from your bash terminal}
\ptindent{\Arrow{} This means copy the below script line and paste it in the bash terminal}
\ptindent{\ \ \ \ \ gawk '\prtobrace x="chmod a-x \%s;";y=sprint(x,\$1);system(y);\prtcbrace' yyy}
\fbreak
Some comments on the above interactive |gawk| program:\fbreak
1) It reads the yyy file where each line read contains 2 fields: filename, and message separated by a space\fbreak
2) It runs the {\it{chmod}} utility by the {\bf{system}} statement\fbreak
3) Not sure about {\bf{chmod}} utility, do a ``man chmod'' on your bash terminal for more information\fbreak
4) If u boobooed on a file and removed the execute attribute, here is a correction:\fbreak
\ptindent{\Arrow{}  {\bf{chmod a+x file-to-reimplement}}}

@<|remove_file_s_execute_attribute|@>=
function remove_file_s_execute_attribute(filename, message)@\
{
  print "Please read |ctan_chk.pdf| to find instructions on how remove execute attribute from a file";
}

@*2 Remove file's with extended attributes.\fbreak
This function is platform dependent.
The {\it{xattr}} is the utility to run on Apple's OSx platform to remove the extension.
@<|remove_file_s_extended_attributes|@>=
function remove_file_s_extended_attributes(filename, message)@\
{
 x="echo %s\";xattr -c %s";
 y=sprintf(x,message,filename);
 print y;
 #y|getline a;
 #close(y); 
}

@*2 Delete file.\fbreak
The file name passed to it is displayed and asks whether it should be deleted.
@<|delete_file|@>=
function delete_file(filename)@\
{
 x="rm -i \"%s\"";
 y=sprintf(x,filename);
 y|getline a;
 close(y); 
}


@* Pass 1 / 2 guidelines assessment and correction.\fbreak
@*2 Pass 1 --- guidelines assessment.\fbreak
Using a text editor (un)comment out the appropriate function calls in |ctan_chk.gawk|  that u'd like to verify.
For example checking just the files to be deleted, comment out all the below functions except
|chk_auxiliary_files|.

U can run pass 1 as is to see whether any of your files for upload do not
pass the guidelines.
From there u can adjust what function to deal with by commenting out the others fuctions
and teeing out its found infidelities for pass 2 correction.

@<pass 1 guidelines verify@>=
function pass1_guidelines_verify(filename)
{
 chk_auxiliary_files(filename);
 chk_extended_file_attributes(filename);
 chk_empty_files(filename);
 chk_empty_directory(filename);
 chk_file_permissions(filename);
 chk_file_to_bypass_in_zip(filename);
}

@*2 Pass 2 --- correct violated guidelines.\fbreak
There are 3 functions whereby 2 of them do usefull things.\fbreak
\ptindent{|delete_file| function asks whether its passed file should be deleted}
\ptindent{\Arrow{} Remove the -i in {\bf{rm -i}} statement if u don't want the interactive question}
\fbreak
\ptindent{|remove_file_s_extended_attributes| function is tailored to the Apple platform}
\ptindent{\Arrow{} Other platforms should have an equivalent {\it{xattr -c}} utility}
\ptindent{\Arrow{} {\bf{Caveat:}} know what utility to use and adjust accordingly to remove the extension attribute}
\ptindent{\Arrow{} Have a read at https://en.wikipedia.org/wiki/Extended\_file\_attributes\#cite\_note-14}
\fbreak
\ptindent{|remove_file_s_execute_attribute| tells u to read the {\bf{ctan\_chk.pdf}} document} 
\ptindent{\Arrow{} on ``how to remove'' the execute attribute from a file}
\fbreak
Uncomment the appropriate below function to call. 
And comment out |pass1_guidelines_verify| statement, and uncomment |pass2_correct| statement
in |Body| action before reruning this program.
@<pass 2 guidelines correction@>=
function pass2_correct(filename, message)
{
 #remove_file_s_execute_attribute(filename,message);
 #remove_file_s_extended_attributes(filename,message);
 #delete_file(filename);
}

@* Gawk Begin, Body, End actions.
@*2 Begin.
@<|BEGIN|@>=
BEGIN{
rec_cnt = 0;
}

@*2 Body.
@<|Body|@>=
{
 pass1_guidelines_verify($1);
 #pass2_correct($1,$2);
}

@*2 END.
@<|END|@>=
END{
#print "no records read: " NR;
}



@ Write out gawk program.
@(ctan_chk.gawk@>=
@<Emit gawk comments@>;
@<|is_file_a_directory|@>;
@<|is_file_an_executable|@>;
@<|chk_auxiliary_files|@>;
@<|remove_file_s_extended_attributes|@>;
@<|chk_file_permissions|@>;
@<|chk_extended_file_attributes|@>;
@<|chk_empty_files|@>;
@<|chk_empty_directory|@>;
@<|delete_file|@>;
@<|chk_file_to_bypass_in_zip|@>;
@<pass 1 guidelines verify@>;
@<pass 2 guidelines correction@>;
@<|BEGIN|@>;
@<|Body|@>;
@<|END|@>;

@** Index.
