22#include <stdlib.h>
33#include <string.h>
44
5+ #include <sys/stat.h>
6+ #include <unistd.h>
7+
58/* Tokens: things which can't be split.
69 * For instance,
710 * TOK_LABEL includes everything from 'import' to 'quit' to 'try'
1316 * TOK_OPERATOR is: * ^ | |= @=
1417 * TOK_EXP is: **
1518 * TOK_PM is: + -
16- * TOK_COMMOLON is: : ,
17- * Note that all our token definitions are by left/right spacing action
18- * For instance, TOK_OPERATOR unconditionally spaces left/right
19- * TOK_COMMOLON inserts a right space unless followed by
20- * TOK_CBRACE
21- * TOK_LABEL has no right gap relative to TOK_OBRACE
22- * TOK_EXP binds close on the left and on the right
23- * TOK_PM acts like TOK_OPERATOR, except when it binds right
19+ * TOK_COLON is: :
2420 */
2521enum {
2622 TOK_LABEL ,
@@ -75,6 +71,21 @@ size_t vlbuf_expand(struct vlbuf *ib, size_t minsize) {
7571 return ib -> len ;
7672}
7773
74+ size_t vlbuf_append (struct vlbuf * ib , const char * str , size_t countedlen ,
75+ FILE * out ) {
76+ int l = strlen (str );
77+ if (ib ) {
78+ if (ib -> len <= l + countedlen + 1 ) {
79+ vlbuf_expand (ib , l + countedlen + 1 );
80+ }
81+ memcpy (& ib -> d .ch [countedlen ], str , l + 1 );
82+ }
83+ if (out ) {
84+ fputs (str , out );
85+ }
86+ return l + countedlen ;
87+ }
88+
7889void vlbuf_free (struct vlbuf * ib ) {
7990 free (ib -> d .vd );
8091 ib -> d .vd = 0 ;
@@ -168,7 +179,8 @@ const char *specnames[] = {"if", "then", "else", "import", "except",
168179 "for" , "while" , "return" , "yield" , "from" ,
169180 "as" , "else" , "finally" , NULL };
170181
171- void pyformat (FILE * file , FILE * out ) {
182+ void pyformat (FILE * file , FILE * out , struct vlbuf * origfile ,
183+ struct vlbuf * formfile ) {
172184 struct vlbuf linebuf = vlbuf_make (sizeof (char ));
173185 struct vlbuf tokbuf = vlbuf_make (sizeof (char ));
174186 struct vlbuf toks = vlbuf_make (sizeof (int ));
@@ -189,6 +201,8 @@ void pyformat(FILE *file, FILE *out) {
189201 int neof = 0 ;
190202 int nestings = 0 ;
191203 int netlen = 0 ;
204+ int origfilelen = 0 ;
205+ int formfilelen = 0 ;
192206 while (1 ) {
193207 char * readct ;
194208 int llen = 0 ;
@@ -197,6 +211,12 @@ void pyformat(FILE *file, FILE *out) {
197211 if (!readct )
198212 break ;
199213 int rlen = strlen (readct );
214+ if (origfile ) {
215+ if (origfile -> len < rlen + origfilelen )
216+ vlbuf_expand (origfile , rlen + origfilelen );
217+ strncpy (& origfile -> d .ch [origfilelen ], & linebuf .d .ch [llen ], rlen );
218+ origfilelen += rlen ;
219+ }
200220 llen += rlen ;
201221 if (linebuf .d .ch [llen - 1 ] != '\n' ) {
202222 vlbuf_expand (& linebuf , llen + 3 );
@@ -528,7 +548,7 @@ void pyformat(FILE *file, FILE *out) {
528548 }
529549
530550 if (line_state == LINE_IS_BLANK && !dumprest ) {
531- fprintf ( out , "\n" );
551+ formfilelen = vlbuf_append ( formfile , "\n" , formfilelen , out );
532552 } else if (line_state == LINE_IS_NORMAL || neof || dumprest ) {
533553 /* Introduce spaces to list */
534554
@@ -666,7 +686,8 @@ void pyformat(FILE *file, FILE *out) {
666686
667687 int length_left = 80 - leading_spaces ;
668688 int first = 1 ;
669- fprintf (out , "%s" , lsp .d .ch );
689+ formfilelen = vlbuf_append (formfile , lsp .d .ch , formfilelen , out );
690+
670691 if (nsplits > 0 ) {
671692 for (int i = 0 ; i < nsplits ; i ++ ) {
672693 int fr = i > 0 ? splitpoints .d .in [i - 1 ] : 0 ;
@@ -683,29 +704,33 @@ void pyformat(FILE *file, FILE *out) {
683704 if ((nlen < length_left || first ) && !force_split ) {
684705 first = 0 ;
685706 length_left -= nlen ;
686- fprintf (out , "%s" , lineout .d .ch );
707+ formfilelen =
708+ vlbuf_append (formfile , lineout .d .ch , formfilelen , out );
687709 } else {
688710 char * prn = & lineout .d .ch [0 ];
689711 if (lineout .d .ch [0 ] == ' ' ) {
690712 prn = & lineout .d .ch [1 ];
691713 nlen -= 1 ;
692714 }
693715 if (force_split || split_nestings .d .in [i - 1 ] > 0 ) {
694- fprintf ( out , "\n " );
716+ formfilelen = vlbuf_append ( formfile , "\n " , formfilelen , out );
695717 } else {
696- fprintf (out , " \\\n " );
718+ formfilelen =
719+ vlbuf_append (formfile , " \\\n " , formfilelen , out );
697720 }
698721 length_left = 80 - leading_spaces - 4 - nlen ;
699- fprintf (out , "%s%s" , lsp .d .ch , prn );
722+ formfilelen = vlbuf_append (formfile , lsp .d .ch , formfilelen , out );
723+ formfilelen = vlbuf_append (formfile , prn , formfilelen , out );
700724 first = 1 ;
701725 }
702726 }
703- fprintf ( out , "\n" );
727+ formfilelen = vlbuf_append ( formfile , "\n" , formfilelen , out );
704728 } else {
705- fprintf (out , "%s\n" , laccum .d .ch );
729+ formfilelen = vlbuf_append (formfile , laccum .d .ch , formfilelen , out );
730+ formfilelen = vlbuf_append (formfile , "\n" , formfilelen , out );
706731 }
707732 if (line_state == LINE_IS_BLANK ) {
708- fprintf ( out , "\n" );
733+ formfilelen = vlbuf_append ( formfile , "\n" , formfilelen , out );
709734 } else {
710735 line_state = LINE_IS_NORMAL ;
711736 }
@@ -738,34 +763,69 @@ int main(int argc, char **argv) {
738763 fprintf (stderr , " (in place) pfai [files]\n" );
739764 }
740765 }
766+
767+ struct vlbuf origfile = vlbuf_make (sizeof (char ));
768+ struct vlbuf formfile = vlbuf_make (sizeof (char ));
769+ int maxnlen = 0 ;
741770 for (int i = 1 ; i < argc ; i ++ ) {
742- const char * name = argv [i ];
771+ int l = strlen (argv [i ]);
772+ if (l > maxnlen )
773+ maxnlen = l ;
774+ }
775+ char * nbuf = (char * )malloc (sizeof (char ) * (maxnlen + 12 ));
743776
777+ for (int i = 1 ; i < argc ; i ++ ) {
778+ const char * name = argv [i ];
744779 FILE * in = fopen (name , "r" );
745780 if (!in ) {
746781 fprintf (stderr , "File %s dne\n" , name );
747782 return 1 ;
748783 }
749-
750- FILE * out ;
751- char buf [24 ];
752- strncpy (buf , ".pfa_XXXXXX" , 23 );
753- if (inplace ) {
754- /* dump to tmp, then copy. Hope it's ram! */
755- int fd = mkstemp (buf );
756- out = fdopen (fd , "w" );
757- } else {
758- out = stdout ;
759- }
760- pyformat (in , out );
784+ /* Format file contents, saving to stdout or to buffers */
785+ pyformat (in , inplace ? 0 : stdout , inplace ? & origfile : 0 ,
786+ inplace ? & formfile : 0 );
761787 fclose (in );
788+
762789 if (inplace ) {
763- fclose (out );
764- int s = rename (buf , name );
765- if (s ) {
766- fprintf (stderr , "Failed to overwrite %s with %s\n" , name , buf );
767- remove (buf );
790+ int unchanged = strcmp (origfile .d .ch , formfile .d .ch ) == 0 ;
791+ if (unchanged ) {
792+ /* Do nothing */
793+ } else {
794+ /* Construct the temporary name */
795+ int l = strlen (name );
796+ strncpy (nbuf , name , l + 1 );
797+ int co = 0 ;
798+ for (int j = l - 1 ; j >= 0 ; j -- )
799+ if (name [j ] == '/' ) {
800+ co = j + 1 ;
801+ break ;
802+ }
803+ strncpy (& nbuf [co ], ".pfa_XXXXXX" , 12 );
804+
805+ /* Write to temporary */
806+ int fo = mkstemp (nbuf );
807+ FILE * out = fdopen (fo , "w" );
808+ fwrite (formfile .d .ch , 1 , strlen (formfile .d .ch ), out );
809+ fclose (out );
810+
811+ /* Ensure properties match */
812+ struct stat st ;
813+ if (stat (name , & st ) < 0 ) {
814+ fprintf (stderr , "Could not get original permissions for %s\n" , name );
815+ } else {
816+ chmod (nbuf , st .st_mode );
817+ chown (nbuf , st .st_uid , st .st_gid );
818+ }
819+
820+ int s = rename (nbuf , name );
821+ if (s ) {
822+ fprintf (stderr , "Failed to overwrite %s with %s\n" , name , nbuf );
823+ remove (nbuf );
824+ }
768825 }
769826 }
770827 }
828+ vlbuf_free (& origfile );
829+ vlbuf_free (& formfile );
830+ free (nbuf );
771831}
0 commit comments