Skip to content

Commit 02170a9

Browse files
author
_
committed
only overwrite file if necessary
1 parent dcde970 commit 02170a9

2 files changed

Lines changed: 98 additions & 38 deletions

File tree

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
all: pfa
33

44
pfa: pfa.c
5-
gcc -Wall -ansi -pedantic -std=c99 -fno-omit-frame-pointer -Os pfa.c -o pfa
5+
gcc -Wall -fno-omit-frame-pointer -Os pfa.c -o pfa
66

77
clean:
8-
rm *.o pfa
8+
rm -f pfa

pfa.c

Lines changed: 96 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
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'
@@ -13,14 +16,7 @@
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
*/
2521
enum {
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+
7889
void 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

Comments
 (0)